Forms 颤振如何使用tabview表单
我正在尝试创建一个具有多个选项卡的表单,但由于某些原因,如果我在表单上调用validate或save,我只能从处于活动状态的选项卡中获取值,对于错误也是如此。我认为这可能是因为表单只从当前在屏幕上呈现的字段中获取值 所以,有人能告诉我如何使表单与多个选项卡视图一起工作,以便在更改选项卡后,我可以验证尚未访问的选项卡以及已授予的选项卡 有AutomaticEpaLiveClientMixin,但它只能使状态保持活动状态,但我更感兴趣的是onSave或validator,因为我是在父元素而不是在选项卡视图中管理状态Forms 颤振如何使用tabview表单,forms,flutter,tabview,Forms,Flutter,Tabview,我正在尝试创建一个具有多个选项卡的表单,但由于某些原因,如果我在表单上调用validate或save,我只能从处于活动状态的选项卡中获取值,对于错误也是如此。我认为这可能是因为表单只从当前在屏幕上呈现的字段中获取值 所以,有人能告诉我如何使表单与多个选项卡视图一起工作,以便在更改选项卡后,我可以验证尚未访问的选项卡以及已授予的选项卡 有AutomaticEpaLiveClientMixin,但它只能使状态保持活动状态,但我更感兴趣的是onSave或validator,因为我是在父元素而不是在选项
提前感谢我与您有相同的需求,我正试图使用一个提供程序来管理不同的表单,该提供程序具有
列表formKeys=[GlobalKey(),GlobalKey()…]代码>每个表单的键。然后在选项卡栏上的一个按钮中按下:form.validate(formKey)用于每个表单。如果所有表单都正常,请保存信息,否则将显示错误消息。我与您有相同的需求,我正在尝试使用具有列表formKeys=[GlobalKey(),GlobalKey()…]的提供程序来管理不同的表单代码>每个表单的键。然后在选项卡栏上的一个按钮中按下:form.validate(formKey)用于每个表单。如果所有表单都正常,请保存信息,否则会显示错误消息。现在我使用的是页面视图和选项卡视图的混合,而不是默认的颤振页面视图。我正在使用此软件包(正如在Flatter默认页面视图中一样,没有预加载选项,但一旦加载页面,我们就可以告诉Flatter保存它,因此此包实际上提供了一个关于应预加载多少页面的选项等。)
然后使用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;
},
),
],
),
),
)
)
)
);
}
}
class IssuseEdit屏幕扩展StatefulWidget{
静态最终路由名称=“/issues\u edit”;
@凌驾
_IssuesEditScreenState createState()=>_IssuesEditScreenState();
}
类_IssuesEditScreenState扩展状态
使用SingleTickerProviderStateMixin{
最终的GlobalKey _form=GlobalKey();
最终_scaffold=GlobalKey();
问题(例如),;
TabController\u TabController;
Preload pageController\u pageController=Preload pageController(
initialPage:0,keepPage:true,viewportFraction:0.99);
bool_canChange=true;
bool\u加载=假;
Map_errors={};
映射_formData={};
@凌驾
无效处置(){
super.dispose();
_tabController.dispose();
_pageController.dispose();
}
@凌驾
void initState(){
//TODO:实现initState
_tabController=tabController(长度:3,vsync:this);
_tabController.addListener((){
if(tab controller.indexIsChanging){
changePage(\u tabController.index,page:true);
}
});
super.initState();
}
作废(提交){
if(!\u form.currentState.validate()){
_当前状态
.showSnackBar(SnackBar(内容:文本(“请解决给定错误”));
返回;
}
_formData.clear();
_form.currentState.save();
}
void changePage(索引,{page=false,tab=false})异步{
若有(第页){
_canChange=假;
等待pageController.animateToPage(索引,
持续时间:持续时间(毫秒:500),曲线:Curves.ease);
_canChange=true;
}否则{
_tabController.animateTo(索引);
}
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
关键词:_脚手架,
appBar:appBar(
标题:文本(“表格”),
底部:选项卡栏(
控制器:\ tab控制器,
选项卡:[
标签(
正文:“第1页”,
),
标签(
正文:“第2页”,
),
选项卡(文本:“第3页”),
],
),
行动:[
扁平按钮(
子项:文本(“保存”),
按下按钮:\ u提交)
],
),
正文:表格(
键:_形式,
子:页面视图(
地址:5,
物理:AlwaysScrollableScrollPhysics(),
控制器:_pageController,
onPageChanged:(索引){
如果(_canChange){
更改页面(索引);
}
},
儿童:[
第1页(formData:_formData,错误:_errors,),
第2页(formData:_formData,错误:_errors),
第3页(formData:\u formData,错误:\u errors)
],
),
),
);
}
}
类Page1扩展了无状态小部件{
常数第1页({
关键点,
@所需的地图格式数据,
@必需的映射错误,
}):_formData=formData,_errors=errors,super(key:key);
最终地图(表格数据);;
最终地图错误;
@凌驾
小部件构建(构建上下文){
返回填充(
填充:常数边集全部(8.0),
孩子:卡片(
标高:3,
孩子:填充(
填充:常数边集全部(8.0),
子:容器(
子:SingleChildScrollView(
子:列(
儿童:[
TextFormField(
onSaved:(值)=>
_formData['field1']=值,
装饰:BorderInputDecorator(
errorText:_errors['field1'],
标签:“字段1”,
),
验证器:(值){
if(value.isEmpty){
返回“此字段为必填字段”;
}
返回null;
},
),
],
),
),
)
)
)
);
}
}
正如您所看到的,您可以使用onsave验证器并添加更多页面,只需在表单上保存或验证即可获得提交中的所有数据
可能存在语法问题目前,我使用的是页面视图和选项卡视图的混合,而不是默认的Flatter页面视图。我正在使用此软件包(正如在Flatter默认页面视图中一样,没有预加载选项,但一旦加载页面,我们可以告诉Flatter保存它,因此此软件包实际上在