Flutter - 单击添加新的小部件

Flutter - Add new Widget on click

我是 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 部分,但我无法让它工作。

有人可以帮忙吗?

这是一种方法

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

List<Widget> children: const <Widget> []

它是一个 List 的小部件。由于 Flutter UI 是在代码中构建的,因此我们可以传递一个我们之前构造的 children 的数组。无需每次都在 [] 中声明它,当您想要在 ColumnRow

中动态 children 时,这会派上用场

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

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

  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

添加一个联系人行

所以我们进行简单的老式迭代,并且对于每次迭代,我们将 ContactRow 添加到我们的 List

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

构造完 List 后,将其作为参数传递给 children。

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

这只是一个简单的例子。 Remember All UI 是用纯代码构建的,您可以将代码构建中的所有知识应用于它。例如, 我们可以提取构建 Column children 的方法,使其更漂亮

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

现在,我们将创建新方法,而不是在构建器方法中创建我们的列表,return 列表本身

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

重要的事情不要忘记,但你的代码中已经有了,就是更新 setState 中的 _count 属性 以便 children 得到重建新_count

只需将 Row 替换为 ListView。

也对 Height/width 进行了一些更改,请查看。

结果: 代码:

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;
    });
  }
}