Flutter как использовать форму с tabview

#forms #flutter #tabview

#формы #flutter #tabview

Вопрос:

Я пытаюсь создать форму с несколькими вкладками, но по какой-то причине, если я вызываю validate или save on form, я могу получить только значения с активной вкладки, и то же самое верно для ошибки, я думаю, это может быть связано с тем, что форма получает значения только из полей, которые в данный момент отображаются на экране.

итак, может ли кто-нибудь сказать мне, как я могу заставить форму работать с несколькими представлениями вкладок, чтобы после смены вкладки я мог проверять вкладки, которые не были посещены, а также принадлежащие им.

существует AutomaticKeepAliveClientMixin, но он может поддерживать только состояние, но меня больше интересует OnSave или validator, поскольку я управляю состоянием в родительском элементе, а не в tabviews

Заранее спасибо

Ответ №1:

У меня такая же потребность, как и у вас, и я пытаюсь управлять различными формами с помощью поставщика, у которого есть List <GlobalKey <FormState>> formKeys = [GlobalKey <FormState> (), GlobalKey <FormState> () ...]; ключ для каждой формы. Затем в кнопке на панели вкладок нажимается: form.validate (formKey) для каждой формы. Если все формы в порядке, сохраните информацию, иначе сообщение об ошибке.

Комментарии:

1. ну, это тоже можно было сделать, и в моей работе у меня было около 20 форм, и в каждой форме было около 20 25 полей, и сначала я использовал form в качестве родительского элемента tabview и передавал все контроллеры редактирования на каждую отдельную вкладку, а при сохранении я выполнял проверки и сохранял все ошибки вотображение ошибок, а затем использование оформления файла для отображения ошибок

2. но затем я нашел другой способ, который на самом деле использует просмотр страниц, и для табуляции я использовал панель вкладок, и есть пакет, который может создавать все страницы сразу, а затем мы можем использовать форму без каких-либо проблем, и я использую это на данный момент

3. можете ли вы поделиться некоторым кодом? Пример с 2 вкладками?

4. хорошо, тогда я пишу новый ответ ниже с примером

5. Это сделано, посмотрите и не стесняйтесь задавать любые вопросы

Ответ №2:

На данный момент я использую сочетание просмотра страниц и просмотра вкладок для страниц вместо просмотра страниц по умолчанию. Я использую этот пакет preload_page_view (как и в представлении страницы по умолчанию flutter, для предварительной загрузки нет опции, но после загрузки страницы мы можем указать flutter сохранить ее, чтобы этот пакет действительно предоставлял возможностьо том, сколько страниц должно быть предварительно загружено и т.д.)

а затем панель вкладок для переключения страниц, подобных этой

 class IssuesEditScreen extends StatefulWidget {
   static final routeName = "/issues_edit";

   @override
   _IssuesEditScreenState createState() => _IssuesEditScreenState();
}

class _IssuesEditScreenState extends State<IssuesEditScreen>
with SingleTickerProviderStateMixin {
   final GlobalKey<FormState> _form = GlobalKey();
   final _scaffold = GlobalKey<ScaffoldState>();

   Issue _instance;
   TabController _tabController;
   PreloadPageController _pageController = PreloadPageController(
       initialPage: 0, keepPage: true, viewportFraction: 0.99);
   bool _canChange = true;
   bool _loading = false;
   Map<String, String> _errors = {};
   Map<String, dynamic> _formData = {};


@override
void dispose() {
   super.dispose();
   _tabController.dispose();
   _pageController.dispose();
}

@override
void initState() {
   // TODO: implement initState
   _tabController = TabController(length: 3, vsync: this);
   _tabController.addListener(() {
   if (_tabController.indexIsChanging) {
       changePage(_tabController.index, page: true);
   }
   });
   super.initState();
}

void _submit() {
   if (!_form.currentState.validate()) {
      _scaffold.currentState
       .showSnackBar(SnackBar(content: Text("Please resolve given errors")));
      return;
   }
   _formData.clear();
   _form.currentState.save();
}
void changePage(index, {page = false, tab = false}) async {
   if (page) {
     _canChange = false;
     await _pageController.animateToPage(index,
       duration: Duration(milliseconds: 500), curve: Curves.ease);
     _canChange = true;
   } else {
     _tabController.animateTo(index);
   }
}

@override
Widget build(BuildContext context) {
 return Scaffold(
   key: _scaffold,
   appBar: AppBar(
     title: Text("Form"),
     bottom: TabBar(
       controller: _tabController,
       tabs: [
         Tab(
           text: "Page1",
         ),
         Tab(
           text: "Page2",
         ),
         Tab(text: "Page3"),
       ],
     ),
     actions: [
       FlatButton(
        child: Text("Save"), 
        onPressed: __submit)
      
      ],
    ),
   body: Form(
     key: _form,
     child: PreloadPageView(
      preloadPagesCount: 5,
      physics: AlwaysScrollableScrollPhysics(),
      controller: _pageController,
      onPageChanged: (index) {
        if (_canChange) {
          changePage(index);
        }
      },
      children: [
        Page1(formData: _formData, errors: _errors,),
        Page2(formData: _formData, errors: _errors),
        Page3(formData: _formData, errors: _errors)
      ],
    ),
  ),
  );
 }
}

class Page1 extends StatelessWidget {
  const Page1 ({
    Key key,
    @required Map<String,dynamic > formData,
    @required Map<String, String> errors,
  }) : _formData = formData, _errors = errors, super(key: key);

 final Map<String,dynamic > _formData;
 final Map<String, String> _errors;

 @override
 Widget build(BuildContext context) {
   return Padding(
    padding: const EdgeInsets.all(8.0),
    child: Card(
        elevation: 3,
        child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Container(
              child: SingleChildScrollView(
                child: Column(
                  children: [
                    TextFormField(
                      onSaved: (value) =>
                      _formData['field1'] = value,
                      decoration: BorderInputDecorator(
                        errorText: _errors['field1'],
                        label: "Field1",
                      ),
                    validator: (value) {
                      if (value.isEmpty) {
                        return "This Field is required";
                       }
                      return null;
                     },
                    ),
                  ],
                ),
              ),
            )
           )
          )
       );
  }
}
 

как вы можете видеть, при этом вы можете использовать валидаторы onsave и добавлять дополнительные страницы, которые просто можно сохранить или проверить в форме, чтобы получить все данные в _submit

Может быть проблема с синтаксисом