【问题标题】:How do I save data from a stateful widget in Flutter?如何在 Flutter 中保存有状态小部件的数据?
【发布时间】:2021-07-01 11:06:16
【问题描述】:

我已经实现了一个允许用户在我的颤振应用程序中输入的 TextField。现在,我想在按下按钮时将用户输入数据保存到变量中,以便以后使用。正如我所看到的,为了实现这一点,我必须创建有状态小部件及其状态的特定实例,以便当我调用小部件以提取变量时,它不会创建带有空文本字段。有问题的文本字段是 ProjectNameField 和 ProjectDescriptionField。 这是我的实现:

ProjectDescriptionField savedDescription = ProjectDescriptionField();
ProjectNameField savedName = ProjectNameField();
AddPage savedPage = AddPage();
_AddPageState savedPageState = _AddPageState();
List<String> image_list_encoded = [];

class AddPage extends StatefulWidget {
  final _AddPageState _addPageState = _AddPageState();
  AddPage({Key? key}) : super(key: key);

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

class _AddPageState extends State<AddPage> {
  List<Asset> images = <Asset>[];
  String _error = NOERROR;
  @override
  Widget build(BuildContext context) {
    if (images.isEmpty)
      return AppLayout(logicalHeight * 0.15);
    else
      return AppLayout(logicalHeight * 0.01);
  }

  List<Asset> getImages() {
    return images;
  }

  Widget AppLayout(double distanceFromImages) {
    return Scaffold(
      appBar: AppBar(
        leading: BackButton(color: Colors.white),
        title: Text(CREATEPROJECT),
        actions: <Widget>[
          IconButton(
            icon: Icon(
              Icons.check,
              color: Colors.white,
            ),
            onPressed: () {
              SavedData _savedData = SavedData(
                  savedName._nameFieldState.myController.value.text,
                  savedDescription
                      ._descriptionFieldState.myController.value.text,
                  savedPage._addPageState.getImages());
              print(_savedData.saved_Project_Description);
              print(_savedData.saved_Project_Name);
              print(_savedData.saved_images.toString());
              saveNewProject(_savedData);
            },
          ),
        ],
      ),
      body: Column(children: <Widget>[
        Padding(
          padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.02, 0, 0),
          child: Center(
              child: Container(
                  height: logicalHeight * 0.05,
                  width: logicalWidth * 0.9,
                  child: savedName)),
        ),
        Padding(
            padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.01, 0, 0),
            child: ElevatedButton(
              child: Text(PICKIMAGES),
              onPressed: loadAssets,
            )),
        Center(
            child: Padding(
                padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.01, 0, 0),
                child: getWidget())),
        Padding(
          padding: EdgeInsets.fromLTRB(
              logicalWidth * 0.05, distanceFromImages, logicalWidth * 0.05, 0),
          child: Center(child: Container(child: savedDescription)),
        ),
      ]),
    );
  }

  Widget getWidget() {
    if (images.length > 0) {
      return Container(
          height: logicalHeight * 0.4,
          width: logicalWidth * 0.8,
          child: ImagePages());
    } else {
      return Padding(
          padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.15, 0, 0),
          child: Container(child: Text(NOPICTURESSELECTED)));
    }
  }

  PageView ImagePages() {
    final PageController controller = PageController(initialPage: 0);
    List<Widget> children = [];
    images.forEach((element) {
      children.add(Padding(
          padding: EdgeInsets.fromLTRB(
              logicalWidth * 0.01, 0, logicalWidth * 0.01, 0),
          child: AssetThumb(
            asset: element,
            width: 1000,
            height: 1000,
          )));
    });
    return PageView(
      scrollDirection: Axis.horizontal,
      controller: controller,
      children: children,
    );
  }
}

class ProjectNameField extends StatefulWidget {
  ProjectNameFieldState _nameFieldState = ProjectNameFieldState();
  @override
  ProjectNameFieldState createState() {
    return _nameFieldState;
  }
}

class ProjectNameFieldState extends State<ProjectNameField> {
  final myController = TextEditingController();
  @override
  void dispose() {
    // Clean up the controller when the widget is disposed.
    myController.dispose();
    super.dispose();
  }

  Widget build(BuildContext context) {
    return TextField(
      controller: myController,
      decoration: InputDecoration(
        border: UnderlineInputBorder(),
        hintText: PROJECTNAME,
      ),
      maxLength: 30,
    );
  }
}

class ProjectDescriptionField extends StatefulWidget {
  ProjectDescriptionFieldState _descriptionFieldState =
      ProjectDescriptionFieldState();
  @override
  ProjectDescriptionFieldState createState() {
    return _descriptionFieldState;
  }
}

class ProjectDescriptionFieldState extends State<ProjectDescriptionField> {
  final myController = TextEditingController();

  @override
  void dispose() {
    // Clean up the controller when the widget is disposed.
    myController.dispose();
    super.dispose();
  }

  Widget build(BuildContext context) {
    return TextField(
      controller: myController,
      decoration: InputDecoration(
        border: UnderlineInputBorder(),
        hintText: PROJECTDESCRIPTION,
      ),
      minLines: 1,
      maxLines: 5,
      maxLength: 5000,
    );
  }
}

class SavedData {
  String saved_Project_Name = "";
  String saved_Project_Description = "";
  List<Asset> saved_images = [];

  SavedData(String saved_Project_Name, String saved_Project_Description,
      List<Asset> saved_images) {
    this.saved_Project_Name = saved_Project_Name;
    this.saved_Project_Description = saved_Project_Description;
    this.saved_images = saved_images;
  }
}

我认为问题出在此处(ProjectNameField 和 ProjectDescriptionField 基本相同,只有细微差别):

class ProjectNameField extends StatefulWidget {
  ProjectNameFieldState _nameFieldState = ProjectNameFieldState();
  @override
  ProjectNameFieldState createState() {
    return _nameFieldState;
  }
}

class ProjectNameFieldState extends State<ProjectNameField> {
  final myController = TextEditingController();
  @override
  void dispose() {
    // Clean up the controller when the widget is disposed.
    myController.dispose();
    super.dispose();
  }

  Widget build(BuildContext context) {
    return TextField(
      controller: myController,
      decoration: InputDecoration(
        border: UnderlineInputBorder(),
        hintText: PROJECTNAME,
      ),
      maxLength: 30,
    );
  }
}

当我让 createState() 返回 _nameFieldState 而不是 ProjectNameFieldState() 时,会出现以下错误:

The createState function for ProjectDescriptionField returned an old or invalid state instance: ProjectDescriptionField, which is not null, violating the contract for createState.
'package:flutter/src/widgets/framework.dart':
Failed assertion: line 4681 pos 7: 'state._widget == null'

但是,当我返回 ProjectNameFieldState() 时,则此代码

onPressed: () {
              SavedData _savedData = SavedData(
                  savedName._nameFieldState.myController.value.text,
                  savedDescription
                      ._descriptionFieldState.myController.value.text,
                  savedPage._addPageState.getImages());
              print(_savedData.saved_Project_Description);
              print(_savedData.saved_Project_Name);
              print(_savedData.saved_images.toString());
              saveNewProject(_savedData);
            }

不保存项目名称。 我怎样才能摆脱这个错误并保存项目名称和项目描述? 谢谢!

【问题讨论】:

    标签: ios flutter statefulwidget


    【解决方案1】:

    您可以使用FormTextFormFiled 小部件轻松地将值保存在变量中并验证表单字段。

    这里是sn-p的代码:

    Form 小部件声明GlobalKey

    final _formKey = GlobalKey<FormState>();
    

    在您将放置TextFormFiledScaffold 正文中,添加Form 小部件作为所有字段的父级

    Form(
        key: _formKey,
        child: Column(children: <Widget>[
          Padding(
            padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.02, 0, 0),
            child: Center(
                child: Container(
                    height: logicalHeight * 0.05,
                    width: logicalWidth * 0.9,
                    child: TextFormField(
                    controller: projectNameController,
                    decoration: InputDecoration(
                        hintText: PROJECTNAME,
                         border: UnderlineInputBorder()),
                         maxLength: 30
                    validator: (value) {
                      if (value.isEmpty) {
                        return 'This is a required field';
                      }
                      return null;
                    },
                    onSaved: (value) => savedProjectName = value),
                )),
          ),
          Padding(
              padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.01, 0, 0),
              child: ElevatedButton(
                child: Text(PICKIMAGES),
                onPressed: loadAssets,
              )),
          Center(
              child: Padding(
                  padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.01, 0, 0),
                  child: getWidget())),
          Padding(
            padding: EdgeInsets.fromLTRB(
                logicalWidth * 0.05, distanceFromImages, logicalWidth * 0.05, 0),
            child: Center(child: Container(child: TextFormField(
                    controller:projectDescriptionController ,
                    decoration: InputDecoration(
                        hintText: PROJECTDESCRIPTION,
                         border: UnderlineInputBorder()),
                          minLines: 1,
                          maxLines: 5,
                          maxLength: 5000,
                    validator: (value) {
                      if (value.isEmpty) {
                        return 'This is a required field';
                      }
                      return null;
                    },
                    onSaved: (value) => savedProjectDescription = value))),
          ),
        ]),
      ),
    

    现在在您的IconButtononPressed 中验证表单并使用保存功能将TextFormField 值保存在您的变量中。

    final form = _formKey.currentState;
              if (form.validate()) {
                form.save();
              }
    

    现在在上面的代码中form.validate() 将调用validatorform.save() 将调用onSaved TextFormField 的属性

    完整代码如下:

    import 'package:flutter/material.dart';
    
    
    class AddPage extends StatefulWidget {
      AddPage({Key? key}) : super(key: key);
    
      @override
      _AddPageState createState() =>
          _AddPageState();
    }
    
    class _AddPageState extends State<AddPage> {
      final _formKey = GlobalKey<FormState>();
      String savedProjectName;
      String savedProjectDescription;
    
      final projectNameController = TextEditingController();
      final projectDescriptionController = TextEditingController();
      double logicalHeight; //your logical height
      double logicalWidth; //your logical widgth
    
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            leading: BackButton(color: Colors.white),
            title: Text(CREATEPROJECT),
            actions: <Widget>[
              IconButton(
                icon: Icon(
                  Icons.check,
                  color: Colors.white,
                ),
                onPressed: () {
                  final form = _formKey.currentState;
                  if (form.validate()) {
                    form.save();
                  } 
                },
              ),
            ],
          ),
          body:Form(
            key: _formKey,
            child: Column(children: <Widget>[
              Padding(
                padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.02, 0, 0),
                child: Center(
                    child: Container(
                        height: logicalHeight * 0.05,
                        width: logicalWidth * 0.9,
                        child: TextFormField(
                        controller: projectNameController,
                        decoration: InputDecoration(
                            hintText: PROJECTNAME,
                             border: UnderlineInputBorder()),
                             maxLength: 30,
                        validator: (value) {
                          if (value.isEmpty) {
                            return 'This is a required field';
                          }
                          return null;
                        },
                        onSaved: (value) => savedProjectName = value),
                    )),
              ),
              Padding(
                  padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.01, 0, 0),
                  child: ElevatedButton(
                    child: Text(PICKIMAGES),
                    onPressed: loadAssets,
                  )),
              Center(
                  child: Padding(
                      padding: EdgeInsets.fromLTRB(0, logicalHeight * 0.01, 0, 0),
                      child: getWidget())),
              Padding(
                padding: EdgeInsets.fromLTRB(
                    logicalWidth * 0.05, distanceFromImages, logicalWidth * 0.05, 0),
                child: Center(child: Container(child: TextFormField(
                        controller:projectDescriptionController ,
                        decoration: InputDecoration(
                            hintText: PROJECTDESCRIPTION,
                             border: UnderlineInputBorder()),
                              minLines: 1,
                              maxLines: 5,
                              maxLength: 5000,
                        validator: (value) {
                          if (value.isEmpty) {
                            return 'This is a required field';
                          }
                          return null;
                        },
                        onSaved: (value) => savedProjectDescription = value),)),
              ),
            ]),
          ),
        );
      }
    
    }
    

    【讨论】:

    • 非常感谢,这完全解决了我的问题!您是否有机会知道是否有类似的方法可以对资产列表执行此操作,而不仅仅是文本,也可能使用表单小部件?
    • @JohannLeidenfrost 对于资产,您可以在选择资产时将它们初始化为变量。
    猜你喜欢
    • 2021-05-19
    • 2019-06-10
    • 2019-09-23
    • 2018-11-24
    • 2020-06-08
    • 2021-08-27
    • 2019-08-29
    • 1970-01-01
    相关资源
    最近更新 更多