Управление проверкой нескольких форм в flutter при просмотре страниц

#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 как решение для управления состоянием, но для упрощения обмена состояниями между виджетами можно использовать и другие решения состояния.

Надеюсь, это поможет!