#flutter #dart
#flutter #dart
Вопрос:
У меня есть несколько форм внутри PageView, формы находятся в разных файлах, таких как registration_form.dart содержит форму регистрации и так далее. В моем приложении каждая страница содержит другую форму. Я хочу, чтобы, когда пользователь нажимал «Продолжить», форма была проверена, и в случае ошибки пользователь будет предупрежден. Я вызываю все страницы в одном классе с именем Body, как показано ниже. Кнопка «Продолжить» находится внутри нее в контейнере непрозрачности. Если есть лучший подход в качестве решения, я открыт для рекомендаций.
@override
Widget build(BuildContext context) {
return SafeArea(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: MediaQuery.of(context).size.height * 0.65,
child: Flex(
direction: Axis.horizontal,
children: [
Flexible(
child: PageView(
controller: _controller,
//physics: new NeverScrollableScrollPhysics(),
children: [
RegisterForm(),
WelcomeForm(),
//CompanyForm(),
//CompanyNextForm(),
//CompanyLogoForm(),
//FinancingDataForm(),
//UtilityForm(),
//MatrixInformationForm(),
//MatrixInformationNextForm(),
//MatrixInformationLastForm(),
//PriceBuildingForm(),
//InstallKitForm(),
//InstallKitDetailedForm(),
//CustomPricingForm(),
//CustomPricingNextForm(),
//FillRow1Form(),
//FillItem1Row1Form(),
//FillItem2Row1Form(),
//FillItem3Row1Form(),
//FillRow2Form(),
//FillItem1Row2Form(),
//FillItem2Row2Form(),
//FillItem3Row2Form(),
//FillRow3Form(),
//FillItem1Row3Form(),
//FillItem2Row3Form(),
//FillItem3Row3Form(),
//InvoicingForm(),
//FinancingForm(),
//FinancingNextForm(),
//FinancingLastForm(),
//FinalizeForm(),
//DoneForm(),
//BookingForm(),
],
),
),
],
),
),
SizedBox(
height: ResponsiveLayout.isSmallScreen(context)
? 10
: ResponsiveLayout.isMediumScreen(context)
? 10
: 10,
),
Opacity(
opacity: 1, //currentIndex == 20 ? 0 : 1,
child: Container(
height: 50,
decoration: BoxDecoration(
color: Color.fromRGBO(16, 88, 198, 1),
borderRadius: BorderRadius.all(Radius.circular(8)),
),
child: GestureDetector(
onTap: () {
_controller.nextPage(
duration: Duration(milliseconds: 300),
curve: Curves.easeIn);
},
child: Container(
width: MediaQuery.of(context).size.width,
height: 100,
decoration: BoxDecoration(
color: Color.fromRGBO(16, 88, 198, 1),
borderRadius: BorderRadius.all(Radius.circular(8)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 100.0,
child: Center(
child: RichText(
text: TextSpan(children: [
WidgetSpan(
child: Text(
'Continue ',
style: TextStyle(
color: Colors.white,
fontSize: ResponsiveLayout
.isSmallScreen(context)
? 12
: ResponsiveLayout.isMediumScreen(
context)
? 12
: 15,
),
)),
WidgetSpan(
child: Icon(
Icons.arrow_forward,
size: ResponsiveLayout.isSmallScreen(
context)
? 12
: ResponsiveLayout.isMediumScreen(
context)
? 12
: 15,
color: Colors.white,
),
),
]),
),
)),
],
),
),
)),
),
],
),
),
);
}
Комментарии:
1. итак, никто не нашел никакого решения для этого? XD
Ответ №1:
Хорошо. Недавно я столкнулся с тем же вопросом и искал хороший подход. Возможно, этот ответ будет полезен любому другому разработчику, ищущему ответ.
Подход
В настоящее время в моем случае я использовал ключи формы для проверок и обратных вызовов функций. Это решение сделало работу за меня, потому что мне нужно было принимать ввод в виде необработанного текста. Другим нравятся варианты с несколькими вариантами выбора, аналогичные тем, где были предопределенные выходные данные.
Чтобы описать мое решение более подробно. Рассмотрим этот пример, мы хотим получить основные сведения о пользователе, такие как имя, возраст, город и т.д. Для пользовательского ввода, такого как имя, мы можем использовать TextFormField
. Это даст доступ к onChanged
обратному вызову для проверки. Для доступа к ответу в PageView
виджете, содержащем класс. Вы можете использовать TextEditingController
.
Теперь мы можем просто добавить Form
виджет в родительский элемент базового build
метода виджета формы.
Наконец, для вопросов с несколькими вариантами ответов. Мы можем предоставить функцию обратного вызова, подобную onTap
виджету PageView
. Эта функция будет вызываться всякий раз, когда пользователь взаимодействует с выпадающим списком или аналогичным виджетом.
Примечание: если у нас есть несколько форм в
PageView
виджете. Вам понадобятся отдельные ключи формы для отдельных форм.
Пример кода
Итак, у нас есть основной form_screen.dart, содержащий PageView
виджет и basic_profile.dart, содержащий нашу форму. Оба файла должны выглядеть примерно так:
form_screen.dart
...
// define the variables and keys here
final _basicProfileKey = GlobalKey<FormState>();
final _userName = TextEditingController();
late String _userGender;
...
// callback function that we will be passing to the BasicProfile
// widget on the other page
void _userGender(String value) {
_userGender = value;
}
...
// the submission callback that will be called whenever the user
// clicks on the next or save button available in the class file
// (this file) containing the PageView widget
void _submissionCallback(){
if(_pageViewIndex == 0) {
final validationStatus = _basicProfileKey.currentState?.validate() ?? false;
if(validationStatus) {
// implement your logic here and then move to next page in the pageview
}
}
}
...
// Build method widget tree containing the PageView and BasicProfile
// widgets
child: PageView(
children: [
BasicProfile(
basicProfileKey: _basicProfileKey,
userName: _userName,
userGenderCallback: userGender
),
]
),
basic_profile.dart
...
// declare the variables for this widget which we will be initialised
// via constructor
final GlobalKey<FormState> basicProfileKey;
final TextEditingController userName;
final Function(String) userGenderCallback;
...
@override
void initState(){
// initialise the default values here if any and call the
// callback function received above
userGenderCallback(_defaultValue);
}
...
Widget build(BuildContext context){
...
child: Form(
key: basicProfileKey,
...
TextFieldForm(
onValidate: (){
// do the validation here
}
)
...
DropDown(
onChanged: (value) {
// logic for validation
userGenderCallback(value);
}
)
}
В моем подходе используется setState
как решение для управления состоянием, но для упрощения обмена состояниями между виджетами можно использовать и другие решения состояния.
Надеюсь, это поможет!