Flutter如何使用表单和tabview

kei*_*gae 5 forms tabview flutter

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

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

有AutomaticKeepAliveClientMixin,但它只能保持状态处于活动状态,但我对 onSave 或验证器更感兴趣,因为我在父元素中而不是在选项卡视图中管理状态

提前致谢

kei*_*gae 1

现在我使用的是页面的 pageview 和选项卡视图的混合,而不是默认的 flutter pageview 我正在使用这个包preload_page_view(就像在 flutter 默认页面视图中一样,没有预加载的选项,但是一旦加载页面,我们就可以告诉 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;
                     },
                    ),
                  ],
                ),
              ),
            )
           )
          )
       );
  }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,您可以使用 onsave 验证器并添加更多页面,只需在表单上保存或验证即可获取 _submit 中的所有数据

可能存在语法问题