如何在 flutter 中访问多个相同状态小部件的 TextEditingController?

how to Access TextEditingController of multiple same Stateful Widgets in flutter?

我正在制作一个应用程序,用户可以在其中的主有状态小部件内的列表视图中添加多个有状态小部件。 示例:配料表。 每个成分小部件都有一个 TextFormField。 用户可以添加任意数量的成分,最终输入的数据将使用来自家庭有状态小部件的 POST 请求进行更新。

问题:如何从主状态访问每个添加的成分小部件的 TextFormField 控制器。 这也是解决这个问题的最佳方法还是有更好的方法?

class home extends StatefulWidget {
  const home({Key? key}) : super(key: key);

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

class _homeState extends State<home> {
  List<Widget> listRecipe = [];

  addIngredient(){
    listRecipe.add(new Ingredient());
  }

  Future<http.Response> postData(){
    return http.post(
      Uri.parse(recipeData),
      headers: <String, String>{
        'Authorization':'token $token',
        'Content-Type': 'application/json; charset=UTF-8',
      },
      body: jsonEncode(<String, String>{
        "name":"something",
        "ingredients":'{"ingredient1": "value", "ingredient2": "value", ...... }'
      }),
    );
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Container(
          child: Wrap(
            children:[ ListView(
              children:listRecipe,
            ),
            ],
          ),
        ),
    ]  ),
      bottomNavigationBar: Row(
          children:
      [FloatingActionButton(
        onPressed: addIngredient,
      ),
        FloatingActionButton(onPressed: postData)
    ]));
  }
}



class Ingredient extends StatefulWidget {
  const Ingredient({Key? key}) : super(key: key);

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

class _IngredientState extends State<Ingredient> {
  final _typeController = TextEditingController();
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Padding(
        padding: EdgeInsets.only(left: 22, top: 20, right: 15),
        child: Column(
          children: [
            Container(
              width: MediaQuery.of(context).size.width,
              child: Padding(
                padding: const EdgeInsets.only(left: 5.0),
                child: Text(
                  "Process",
                  style: TextStyle(
                    fontFamily: 'Nunito',
                    color: Colors.grey.shade500,
                    fontSize: 12,
                  ),
                  textAlign: TextAlign.left,
                ),
              ),
            ),
            Container(
              height: 45,
              child: TextFormField(
                keyboardType: TextInputType.text,
                maxLines: null,
                controller: _typeController,
                style: TextStyle(fontSize: 15, fontFamily: 'Nunito'),
                decoration: InputDecoration(
                  hintText: 'Enter Process',
                  hintStyle: TextStyle(color: Colors.grey.shade400),
                  contentPadding: EdgeInsets.only(left: 5),
                  enabledBorder: UnderlineInputBorder(
                      borderSide: BorderSide(color: Colors.green)),
                  focusedBorder: UnderlineInputBorder(
                    borderSide: BorderSide(color: Colors.green, width: 2),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );;
  }
}

tl:dr

  • 将最终字符串 属性 添加到您的 StatefulWidget
  • 在 initState 中将 属性 的值分配给 TextEditingController: textEditingController.text = widget.stringValue
  • 覆盖 didUpdateWidget 并设置 TextEditingControllerValue textEditingController.text = widget.stringValue

我建议为您的成分添加一个模型,例如:

class Ingredient {
  String? data;

  Ingredient({this.data});
}

将 Ingredient Widget 重命名为例如IngredientWidget。你的 listReceipe 的类型应该保持 List<Ingredient>:

  List<Ingredient> listRecipe = [];

  addIngredient() {
    setState(() {
      listRecipe.add(Ingredient());
    });
  }

更改主页小部件的主体:

 body: Container(
              child: ListView.builder(
                  itemCount: listRecipe.length,
                  itemBuilder: (context, index) =>
                      IngredientWidget(listRecipe[index]))),

现在像这样更改您的 IngredientWidget:

class IngredientWidget extends StatefulWidget {
  const IngredientWidget(this.ingredient, {Key? key}) : super(key: key);

  final Ingredient ingredient;

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

class _IngredientWidgetState extends State<IngredientWidget> {
  final _typeController = TextEditingController();

  @override
  void didUpdateWidget(covariant IngredientWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    _typeController.text = widget.ingredient.data ?? '';
  }

  @override
  void initState() {
    super.initState();
    _typeController.text = widget.ingredient.data ?? '';
  }

  @override
  Widget build(BuildContext context) {
    // stays the same
  }
}

您可以将值传递给成分小部件:

Ingredient(data: 'Hello World')

因此,您还可以使用

更新 listReceipe 中的成分
  setState(() {
    listRecipe[index] = Ingredient(data: anyStringValue);
  });

您的列表应该会相应更新。