【问题标题】:Flutter how to use form with tabviewFlutter 如何在 tabview 中使用表单
【发布时间】:2021-03-04 19:33:17
【问题描述】:

我正在尝试创建一个带有多个选项卡的表单,但由于某种原因,如果我在表单上调用验证或保存,我只能从处于活动状态的选项卡中获取值,对于错误也是如此,我认为这可能是因为表单只能获取当前在屏幕上呈现的字段的值。

有人可以告诉我如何使表单与多个选项卡视图一起工作,以便在更改选项卡后我可以验证尚未访问的选项卡以及既得的选项卡。

有 AutomaticKeepAliveClientMixin,但它只能保持状态,但我对 onSave 或验证器更感兴趣,因为我在父元素中而不是在 tabviews 中管理状态

提前致谢

【问题讨论】:

    标签: forms flutter tabview


    【解决方案1】:

    我和你有同样的需求,我正在尝试使用每个表单都有一个 List <GlobalKey <FormState>> formKeys = [GlobalKey <FormState> (), GlobalKey <FormState> () ...]; 键的 Provider 来管理不同的表单。然后在tabbar上的一个按钮onPressed:form.validate(formKey)为每个表单。如果所有表单都正常,请保存信息,否则会出现错误消息。

    【讨论】:

    • 它也可以完成,在我的工作中,我有大约 20 个表单,每个表单有大约 20 25 个字段,首先我所做的是使用表单作为 tabview 的父级并通过所有编辑控制器到每个单独的选项卡,保存时我将进行验证并将所有错误保存在错误映射中,然后使用归档装饰来显示错误
    • 但后来发现了另一种实际使用页面浏览和标签的方式,我使用了标签栏,并且有一个可以一次构建所有页面的包,然后我们可以毫无问题地使用表单,我是暂时用这个
    • 你能分享一些代码吗?有 2 个标签的示例?
    • 好的,那么我正在用示例写一个新的答案
    • 看完了,有什么问题可以随时问
    【解决方案2】:

    现在我使用的是页面视图和选项卡视图的混合,而不是默认的颤振页面视图我正在使用这个包preload_page_view(在颤振默认页面视图中没有预加载选项,但是一旦页面是加载后我们可以告诉flutter保存它,所以这个包实际上提供了一个关于应该预加载多少页等的选项。)

    然后Tabbar这样切换页面

    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 中的所有数据

    可能存在语法问题

    【讨论】:

      猜你喜欢
      • 2022-06-29
      • 1970-01-01
      • 1970-01-01
      • 2021-09-23
      • 2022-09-26
      • 2018-12-21
      • 2020-09-04
      • 2021-03-31
      • 2021-12-11
      相关资源
      最近更新 更多