【问题标题】:Flutter - Add new Widget on clickFlutter - 单击时添加新的小部件
【发布时间】:2018-11-19 12:47:52
【问题描述】:

我是 Flutter 的新手,我正在尝试构建一个相当简单的应用程序。 我有这个简单(并且仍在进行中)的代码,并且每次用户单击按钮时我都会尝试添加一个新的小部件。

这是我的代码:

class ResponsavelProfilePage extends StatefulWidget {
  @override
  _ResponsavelProfilePageState createState() => new _ResponsavelProfilePageState();
}

class _ResponsavelProfilePageState extends State<ResponsavelProfilePage> {

  int _count = 1;

  @override
  Widget build(BuildContext context) {
    List<Widget> _contatos = new List.generate(_count, (int i) => new ContactRow());

    return new Scaffold(
        appBar: new AppBar(
          title: new Text(GlobalConstants.appName),
        ),
        body: new LayoutBuilder(builder: (context, constraint) {
          final _maxHeight = constraint.biggest.height / 3;
          final _biggerFont = TextStyle(fontSize: _maxHeight / 6);

          return new Center(
            child: new Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                new TextFormField(
                  decoration: new InputDecoration(
                    labelText: 'Nome',
                  ),
                ),
                new Container(
                  padding: new EdgeInsets.all(20.0),
                ),
                new TextFormField(
                  decoration: new InputDecoration(
                    labelText: 'Data de nascimento',
                  ),
                ),
                new Container(
                  padding: new EdgeInsets.all(20.0),
                ),
                new Row(
                  children: _contatos,
                ),
                new FlatButton(
                    onPressed:  _addNewContactRow,
                  child: new Icon(Icons.add),
                ),
                //new ContactRow()
              ],
            ),
          );
        })
    );
  }

  void _addNewContactRow() {
    setState(() {
      _count = _count + 1;
    });
  }
}

class ContactRow extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _ContactRow();

}

class _ContactRow extends State<ContactRow> {
  @override
  Widget build(BuildContext context) {
    return new Container(
        child:
        new Column(
            children: <Widget>[
              new TextFormField(
                decoration: new InputDecoration(
                  labelText: 'Contato',
                ),
              ),
              new Text("Tipo Contato: "),
              new DropdownButton(
                value: _currentContactType,
                items: _dropDownMenuItems,
                onChanged: changedDropDownItem,
              ),
              new Container(
                padding: new EdgeInsets.all(20.0),
              ),
            ]
        )
    );
  }

  List _contactTypes =
  ["Phone (SMS)", "Phone (Whatsapp)", "Email"];

  List<DropdownMenuItem<String>> _dropDownMenuItems;
  String _currentContactType;

  @override
  void initState() {
    _dropDownMenuItems = getDropDownMenuItems();
    _currentContactType = null;
    super.initState();
  }

  List<DropdownMenuItem<String>> getDropDownMenuItems() {
    List<DropdownMenuItem<String>> items = new List();
    for (String city in _contactTypes) {
      items.add(new DropdownMenuItem(
          value: city,
          child: new Text(city)
      ));
    }
    return items;
  }

  void changedDropDownItem(String selectedCity) {
    setState(() {
      _currentContactType = selectedCity;
    });
  }
}

当用户单击带有 onPressed 上的 addNewContactRow() 的平面按钮时,我想添加另一个 ContactRow。 我在 addNewContactRow() 上找到了代码,在另一个问题上找到了 List.generate 部分,但我无法让它工作。

有人可以帮忙吗?

【问题讨论】:

    标签: android dart flutter flutter-layout


    【解决方案1】:

    这是一种方法

    首先,让我们看看children 列的属性是什么。

    List&lt;Widget&gt; children: const &lt;Widget&gt; []

    它是一个List 的小部件。由于 Flutter UI 是在代码中构建的,因此我们可以传递我们之前构建的子数组。无需每次都在[] 中声明它,当您想要在ColumnRow 中使用动态子代时,这很方便

    在您的构建器中,您返回包装列的Center 小部件。由于 builder 是一个函数,我们可以在返回 Widget 之前做一些魔术。

    让我们首先从一个变量中的列本身中提取数组:

      List<Widget> extractedChildren = <Widget>[
        new TextFormField(
          decoration: new InputDecoration(
            labelText: 'Nome',
          ),
        ),
        new Container(
          padding: new EdgeInsets.all(20.0),
        ),
        new TextFormField(
          decoration: new InputDecoration(
            labelText: 'Data de nascimento',
          ),
        ),
        new Container(
          padding: new EdgeInsets.all(20.0),
        ),
        new Row(
          children: _contatos,
        ),
        new FlatButton(
          onPressed: _addNewContactRow,
          child: new Icon(Icons.add),
        ),
        //new ContactRow()
      ];
    

    现在,这是您目前拥有的专栏。看看你的问题,你现在想做的是为每个_count添加一个联系人行

    所以我们进行了简单的老式迭代,每次迭代我们在List 中添加一个ContactRow

      for (var i = 0; i < _count; ++i) {
        extractedChildren.add(ContactRow());
      }
    

    在我们构造好 List 之后,将它作为参数传递给孩子。

     return new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: extractedChildren,
        ),
      );
    

    这只是一个简单的例子。请记住,所有 UI 都是用纯代码构建的,您可以将代码构建中的所有知识应用到它上面。例如, 我们可以提取方法来构建 Column 的孩子,使其更漂亮

        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: createChildren(),
        ),
    

    现在,我们将创建返回 List 自身的新方法,而不是在 builder 方法中创建 List

    List<Widget> createChildren(){
    //same code for creating the list
    }
    

    不要忘记重要的事情,但您的代码中已经有了它,是更新 setState 中的 _count 属性,以便使用新的 _count 重建孩子

    【讨论】:

    • 我想在您的回答中看到详细信息,即描述您的建议。
    • 现在我可以听从你的回答了。看起来很不错!
    【解决方案2】:

    只需将 Row 替换为 ListView。

    还对高度/宽度做了一些改动,看看吧。

    结果: 代码:

    import 'package:flutter/material.dart';
    
    void main() => runApp(
          new MaterialApp(
            home: new ResponsavelProfilePage(),
          ),
        );
    
    class ResponsavelProfilePage extends StatefulWidget {
      @override
      _ResponsavelProfilePageState createState() =>
          new _ResponsavelProfilePageState();
    }
    
    class _ResponsavelProfilePageState extends State<ResponsavelProfilePage> {
      int _count = 1;
    
      @override
      Widget build(BuildContext context) {
        List<Widget> _contatos =
            new List.generate(_count, (int i) => new ContactRow());
    
        return new Scaffold(
            appBar: new AppBar(
              title: new Text("NonstopIO"),
            ),
            body: new LayoutBuilder(builder: (context, constraint) {
              final _maxHeight = constraint.biggest.height / 3;
              final _biggerFont = TextStyle(fontSize: _maxHeight / 6);
    
              return new Center(
                child: new Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    new TextFormField(
                      decoration: new InputDecoration(
                        labelText: 'Nome',
                      ),
                    ),
                    new Container(
                      padding: new EdgeInsets.all(20.0),
                    ),
                    new TextFormField(
                      decoration: new InputDecoration(
                        labelText: 'Data de nascimento',
                      ),
                    ),
                    new Container(
                      padding: new EdgeInsets.all(20.0),
                    ),
                    new Container(
                      height: 200.0,
                      child: new ListView(
                        children: _contatos,
                        scrollDirection: Axis.horizontal,
                      ),
                    ),
                    new FlatButton(
                      onPressed: _addNewContactRow,
                      child: new Icon(Icons.add),
                    ),
                    //new ContactRow()
                  ],
                ),
              );
            }));
      }
    
      void _addNewContactRow() {
        setState(() {
          _count = _count + 1;
        });
      }
    }
    
    class ContactRow extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => new _ContactRow();
    }
    
    class _ContactRow extends State<ContactRow> {
      @override
      Widget build(BuildContext context) {
        return new Container(
            width: 170.0,
            padding: new EdgeInsets.all(5.0),
            child: new Column(children: <Widget>[
              new TextFormField(
                decoration: new InputDecoration(
                  labelText: 'Contato',
                ),
              ),
              new Text("Tipo Contato: "),
              new DropdownButton(
                value: _currentContactType,
                items: _dropDownMenuItems,
                onChanged: changedDropDownItem,
              ),
              new Container(
                padding: new EdgeInsets.all(20.0),
              ),
            ]));
      }
    
      List _contactTypes = ["Phone (SMS)", "Phone (Whatsapp)", "Email"];
    
      List<DropdownMenuItem<String>> _dropDownMenuItems;
      String _currentContactType;
    
      @override
      void initState() {
        _dropDownMenuItems = getDropDownMenuItems();
        _currentContactType = null;
        super.initState();
      }
    
      List<DropdownMenuItem<String>> getDropDownMenuItems() {
        List<DropdownMenuItem<String>> items = new List();
        for (String city in _contactTypes) {
          items.add(new DropdownMenuItem(value: city, child: new Text(city)));
        }
        return items;
      }
    
      void changedDropDownItem(String selectedCity) {
        setState(() {
          _currentContactType = selectedCity;
        });
      }
    }
    

    【讨论】:

    • 嗨,Ajay,谢谢这个工作正常!就我而言,我做了一些更改并在列表中添加了TextFormField。我不确定如何从列表中获取控制器和输入值。你能建议一些方法来得到它吗?感谢您的帮助!
    猜你喜欢
    • 2017-09-25
    • 2020-08-13
    • 1970-01-01
    • 2019-08-23
    • 2021-01-13
    • 1970-01-01
    • 2021-05-01
    • 2022-12-18
    • 2011-07-07
    相关资源
    最近更新 更多