Мне нужно подготовить экран для создания новой записи для таблицы с несколькими полями. Некоторые поля зависят от предыдущих полей. Моя первоначальная попытка включает набор TabController/TabBarView/Tabs, где каждая вкладка является частью формы.
Мои две проблемы:
Кажется, я не могу скрыть саму «вкладку» (значок/текст) в TabBarView (я хочу использовать кнопку «Следующий шаг»)
Даже если я буду жить с этим, если я создам виджет для каждой вкладки, мне понадобится GlobalKey для каждой формы (по одному для каждой вкладки), поскольку ими нельзя поделиться.
Есть ли другой способ сделать это, с другим виджетом или подходом, чтобы разделить форму на несколько шагов/экранов, а затем отправить все данные целиком?




Я думаю, что нашел лучший способ справиться с этим. Я вообще отброшу вкладки (хотя я думаю, что можно «встроить» эту логику во вкладки), так как кнопок «Далее / Предыдущий» может быть достаточно. Таким образом я сохраняю единую форму (ключ), и в момент сохранения она работает отлично.
import 'package:flutter/material.dart';
final _formKey = GlobalKey<FormState>();
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sandbox',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Sandbox'),
),
body: Container(
padding: EdgeInsets.all(8.0),
color: Colors.white,
child: FormWidget(),
),
);
}
}
class FormWidget extends StatefulWidget {
@override
_FormWidgetState createState() => _FormWidgetState();
}
class _FormWidgetState extends State<FormWidget> {
int _stepNumber = 1;
final ctl_name = TextEditingController();
final ctl_age = TextEditingController();
final ctl_address = TextEditingController();
final ctl_city = TextEditingController();
void saveData(BuildContext context) {
_formKey.currentState.save();
print(ctl_name.text);
print(ctl_age.text);
print(ctl_address.text);
print(ctl_city.text);
}
void nextPage(BuildContext context) {
setState(() {
if (_stepNumber == 1)
_stepNumber = 2;
else
_stepNumber = 1;
});
}
Column formOneBuilder(BuildContext context) {
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(border: Border.all(color: Colors.blue)),
width: double.infinity,
child: Text("STEP 1")
),
),
TextFormField(
controller: ctl_name,
decoration: const InputDecoration(
labelText: 'Step 1 Name'
),
),
TextFormField(
controller: ctl_age,
decoration: const InputDecoration(
labelText: 'Step 2 Age'
),
),
Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FlatButton(
color: Colors.blue,
child: Text('Next'),
onPressed: () {nextPage(context);} ,
),
Padding(padding: EdgeInsets.only(left: 8)),
FlatButton(
color: Colors.blue,
child: Text('Save'),
onPressed: () {saveData(context);} ,
),
],
),
),
)
],
);
}
Column formTwoBuilder(BuildContext context) {
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(border: Border.all(color: Colors.red)),
width: double.infinity,
child: Text("STEP 2"),
),
),
TextFormField(
controller: ctl_address,
decoration: const InputDecoration(
labelText: 'Step 2 Address'
),
),
TextFormField(
controller: ctl_city,
decoration: const InputDecoration(
labelText: 'Step 2 City'
),
),
Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FlatButton(
color: Colors.blue,
child: Text('Previous'),
onPressed: () {nextPage(context);} ,
),
Padding(padding: EdgeInsets.only(left: 8)),
FlatButton(
color: Colors.blue,
child: Text('Save'),
onPressed: () {saveData(context);} ,
),
],
),
),
)
],
);
}
@override
Widget build(BuildContext context) {
switch (_stepNumber) {
case 1:
return Form(
key: _formKey,
child:
this.formOneBuilder(context),
);
break;
case 2:
return Form(
key: _formKey,
child:
this.formTwoBuilder(context),
);
break;
}
}
void dispose() {
ctl_address.dispose();
ctl_age.dispose();
ctl_city.dispose();
ctl_name.dispose();
super.dispose();
}
}
Вы можете использовать Stepper Widget. это может позволить вам создать вертикальный или горизонтальный мастер из нескольких шагов.
Stepper({
Key key,
@required this.steps,
this.physics,
this.type = StepperType.vertical,
this.currentStep = 0,
this.onStepTapped,
this.onStepContinue,
this.onStepCancel,
this.controlsBuilder,
})
Вы можете последовать этому примеру, Пол Холлидейhttps://developer.school/flutter-how-to-use-the-stepper-widget/
@GregoryRay извините, я на некоторое время покинул Flutter, и конкретно для этого проекта я выбрал свое решение ниже, но ваше было очень полезно для других вопросов, так что да, определенно принято. Спасибо.
Это похоже на решение, которое мне нужно. Спасибо попробую как можно скорее!