Форма с несколькими шагами (стиль мастера) во Flutter — лучший подход

Мне нужно подготовить экран для создания новой записи для таблицы с несколькими полями. Некоторые поля зависят от предыдущих полей. Моя первоначальная попытка включает набор TabController/TabBarView/Tabs, где каждая вкладка является частью формы.

Мои две проблемы:

  • Кажется, я не могу скрыть саму «вкладку» (значок/текст) в TabBarView (я хочу использовать кнопку «Следующий шаг»)

  • Даже если я буду жить с этим, если я создам виджет для каждой вкладки, мне понадобится GlobalKey для каждой формы (по одному для каждой вкладки), поскольку ими нельзя поделиться.

Есть ли другой способ сделать это, с другим виджетом или подходом, чтобы разделить форму на несколько шагов/экранов, а затем отправить все данные целиком?

JS - События опций формы
JS - События опций формы
В продолжение предыдущей статьи CSS - стили, связанные с вводом формы , в этой статье мы будем использовать JS для взаимодействия с формами, на этот...
CSS - Стили, связанные с вводом формы
CSS - Стили, связанные с вводом формы
Общими стилями ввода для форм являются Input (включая Text, Radio, checkbox), Select и Textarea, из которых Input относительно прост, поэтому в этой...
Создание многостраничной формы заявления о приеме на работу с помощью Angular
Создание многостраничной формы заявления о приеме на работу с помощью Angular
Наличие на корпоративном сайте форм заявлений о приеме на работу, или "трудовых анкет", экономит время и деньги как для соискателей, так и для...
10
0
12 937
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я думаю, что нашел лучший способ справиться с этим. Я вообще отброшу вкладки (хотя я думаю, что можно «встроить» эту логику во вкладки), так как кнопок «Далее / Предыдущий» может быть достаточно. Таким образом я сохраняю единую форму (ключ), и в момент сохранения она работает отлично.

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/

Это похоже на решение, которое мне нужно. Спасибо попробую как можно скорее!

cdsaenz 20.04.2020 02:57

@GregoryRay извините, я на некоторое время покинул Flutter, и конкретно для этого проекта я выбрал свое решение ниже, но ваше было очень полезно для других вопросов, так что да, определенно принято. Спасибо.

cdsaenz 03.11.2020 00:58

Другие вопросы по теме