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

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

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

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

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


person kei nagae    schedule 21.11.2020    source источник


Ответы (2)


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

person ctechdev.io    schedule 22.12.2020
comment
ну, это тоже можно было сделать, и в моей работе у меня было около 20 форм, и каждая форма имела около 20 25 полей, и сначала я использовал форму как родительскую для tabview и передавал все контроллеры редактирования на каждую отдельную вкладку и при сохранении Я буду делать проверки и сохранял все ошибки в карте ошибок, а затем использовал оформление поля, чтобы показать ошибки - person kei nagae; 26.12.2020
comment
но затем нашел другой способ, который фактически использовал просмотр страницы и для табуляции, я использовал панель вкладок, и есть пакет, который может создавать все страницы сразу, а затем мы можем использовать форму без каких-либо проблем, и я использую это в настоящее время - person kei nagae; 26.12.2020
comment
можешь поделиться кодом? Пример с 2 вкладками? - person ctechdev.io; 26.12.2020
comment
хорошо, тогда я пишу новый ответ ниже с примером - person kei nagae; 27.12.2020
comment
Отлично, заранее спасибо - person ctechdev.io; 27.12.2020
comment
Это сделано, посмотрите и не стесняйтесь спрашивать любые вопросы - person kei nagae; 27.12.2020

На данный момент я использую сочетание просмотра страниц и вкладок для страниц вместо просмотра страниц по умолчанию. Я использую этот пакет 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

Возможна проблема с синтаксисом

person kei nagae    schedule 27.12.2020