【问题标题】:Flutter - Create dynamic number of texteditingcontrollersFlutter - 创建动态数量的文本编辑控制器
【发布时间】:2018-06-08 17:58:44
【问题描述】:

我正在重新创建一个我以前用 Swift 制作的应用程序,在我的一个页面上,我们调用一个 API,并根据结果,我们向用户显示动态数量的文本字段,以通过不同的搜索参数进行搜索。

在 Dart/Flutter 中有什么好的方法可以做到这一点吗?由于 dart 不支持在运行时生成代码,这甚至有可能吗?

【问题讨论】:

  • 只需使用列表或映射来保存引用,无需生成代码。
  • @GünterZöchbauer 你能告诉我如何使用地图实例化一个新变量吗?例如,如果我有 3 个参数,我将需要 3 个文本编辑控制器。因此,我试图考虑如何循环并创建 3 个新的文本编辑控制器,例如名为 textController1、textController2、textController3。在保持这种动态的同时,我可以拥有任意数量的它们。
  • 这正是我也在寻找的。您是否设法解决了问题或找到了解决方法? @MattLampe

标签: dynamic dart flutter


【解决方案1】:

我刚刚修改了@Felix 的答案,使用 Map 来存储 TextEditingControllers 而不是列表。我认为用键值对调用 textEditingControllers 很容易。 修改代码块;

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "MyHomePage",
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(
        title: "MyHomePage",
      ),
    );
  }
}
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final title;

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

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    var stringListReturnedFromApiCall = ["first", "second", "third", "fourth", "..."];
    // This list of controllers can be used to set and get the text from/to the TextFields
    Map<String,TextEditingController> textEditingControllers = {};
    var textFields = <TextField>[];
    stringListReturnedFromApiCall.forEach((str) {
      var textEditingController = new TextEditingController(text: str);
      textEditingControllers.putIfAbsent(str, ()=>textEditingController);
      return textFields.add( TextField(controller: textEditingController));
    });

    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: SingleChildScrollView(
            child: new Column(
              children:[
              Column(children:  textFields),
                RaisedButton(
                  child: Text("Print Values"),
                    onPressed: (){
                    stringListReturnedFromApiCall.forEach((str){
                      print(textEditingControllers[str].text);
                    });
                  })
              ]
            )));
  }
}

当您向文本字段写入内容并点击打印按钮结果时;

flutter: first controller text
flutter: second controller text
flutter: third controller text
flutter: fourth controller text
flutter: so on .......

【讨论】:

  • 你如何处理那些TextEditingControllers?
  • @override void dispose() { textEditingControllers.forEach((_,v){ v.dispose(); }); super.dispose(); }
  • 这里如何更新文本字段值 textEditingControllers[0].text='test';但它会更新控制器而不是文本字段对此有任何想法吗?
  • 因此您应该将 textEditingControllers[0] 添加到 Textfield 的控制器属性中,以便 textfield 识别该值。
  • @LutfiArdiansyah 不客气,很高兴听到这个消息。
【解决方案2】:

或多或少就像@Günter Zöchbauer 提到的那样,您可以构建一个嵌套在容器中的小部件列表。

这是一个简单的例子:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "MyHomePage",
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(
        title: "MyHomePage",
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    var stringListReturnedFromApiCall = ["first", "second", "third", "fourth", "..."];

    // This list of controllers can be used to set and get the text from/to the TextFields
    var textEditingControllers = <TextEditingController>[];

    var textFields = <TextField>[];
    stringListReturnedFromApiCall.forEach((str) {
      var textEditingController = new TextEditingController(text: str);
      textEditingControllers.add(textEditingController);
      return textFields.add(new TextField(controller: textEditingController));
    });

    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: SingleChildScrollView(
            child: new Column(
          children: textFields,
        )));
  }
}

编辑:为TextEditingControllers 添加列表以与所有TextFields 交互

【讨论】:

  • 没有任何参考就创建本地TextEditingController是没有用的。 TextEditingController 通常用于从 TextField 获取文本并将文本设置为 TextField,而这些不能用这个来完成。
  • 我在例子中实例化的TextEditingController可以用来定义TextField的默认值以及从中获取值。 TextFields,没有完整的实现。
  • @Felix 您如何从示例中创建的文本字段中获取值?
  • 您可以遍历textEditingControllers-list 并访问text 属性以读取当前值。
【解决方案3】:

使用 textEditingControllers 列表代替地图

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final title;

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

class _MyHomePageState extends State<MyHomePage> {
  var stringListReturnedFromApiCall = ["first", "second", "third", "fourth", "..."];
  List<TextEditingController> textEditingControllers = [];

  @override
  void initState() {
    super.initState();
    stringListReturnedFromApiCall.forEach((String str) {
      var textEditingController = TextEditingController(text: str);
      textEditingControllers.add(textEditingController);
    });
  }

  @override
  void dispose() {
    super.dispose();
    // dispose textEditingControllers to prevent memory leaks
    for (TextEditingController textEditingController in textEditingControllers) {
      textEditingController?.dispose();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('title'),
      ),
      body: ListView.builder(
        itemCount: stringListReturnedFromApiCall.length,
        itemBuilder: (BuildContext context, int index) {
          return Padding(
            padding: const EdgeInsets.all(10.0),
            child: TextField(
              controller: textEditingControllers[index],
            ),
          );
        },
      ),
    );
  }
}

【讨论】:

    【解决方案4】:

    这可能对您或其他人也有帮助。

    createFieldsList(context) {
        thirdStepUserRegistration.value.forEach((key, value) { //// This line will loop all your data [ValueNotifier<Map<String, dynamic>> thirdStepUserRegistration]
          if (!fieldsController.containsKey(key)) {
            fieldsController[key] = TextEditingController(); //// This one will create you a list of controllers that u need for your fiels [Map<String, TextEditingController> fieldsController]
            fieldsList.add( ////You will be creating a list of widget which is textfields [List<Widget> fieldsList]
              Container(
                height: 40.0,
                margin: EdgeInsets.only(bottom: 10),
                width: MediaQuery.of(context).size.width - 100,
                child: PrimaryTextFormField( //This is my customize textfield you can create yours
                  controller: fieldsController[key],
                  keyboardType: TextInputType.text,
                  textCapitalization: TextCapitalization.words,
                  inputFormatters: textFormatter(),
                  hintText: value,
                ),
              )
            );
          }
        });
      }
    
      Column additionalDetails(BuildContext context) {
        createFieldsList(context);
        return Column( children: fieldsList );
      }
    

    【讨论】:

    • 请您添加一些解释以提高对解决方案的理解?
    【解决方案5】:

    包含您的控制器的列表

         var myControllers = []; 
            
    

    为了填充 myControllers 而调用的函数

              createControllers() {
                myControllers = [];
                for (var i = 0; i < your_items.length; i++) {
                  myControllers.add(TextEditingController());
                }
              }
    

    在你的 statefullwidget 中初始化 createKeys 像这样使用它,例如在 listview builder 中;

    TextField(
              controller: myControllers[index],
            ),
    

    【讨论】:

      猜你喜欢
      • 2021-09-19
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-21
      • 1970-01-01
      • 2021-05-17
      • 2014-02-15
      相关资源
      最近更新 更多