【问题标题】:State update in parent widget not reflected in child widget父小部件中的状态更新未反映在子小部件中
【发布时间】:2019-10-24 16:07:17
【问题描述】:

我有一个小部件Players,代码如下:

class Players extends StatefulWidget {
  List<Player> players;
  Players(this.players);
  static const pageName = 'Players';
  static const routeName = '/Players';
  @override
  _PlayersState createState() => _PlayersState();
}

class _PlayersState extends State<Players> {
  final _formKey = GlobalKey<FormState>();
  @override
  Widget build(BuildContext context) {
    var _players = widget.players;
    return Scaffold(
      appBar: CustomAppBar(loggedInPlayer.balance),
      body: SafeArea(
          child: ListView(children: <Widget>[
        Container(
            padding: EdgeInsets.only(left: 10, right: 10, top: 10),
            child: Form(
              key: _formKey,
              child: TextFormField(
                onFieldSubmitted: (name) {
                  setState(() {
                    _players = players.where((x) =>
                        x.name.toLowerCase().contains(name.toLowerCase()));
                  });
                },
                decoration: InputDecoration(
                  fillColor: Colors.white,
                  hintText: 'Search a player by name',
                  contentPadding: EdgeInsets.all(10),
                  border: OutlineInputBorder(),
                ),
                // The validator receives the text that the user has entered.
                validator: (value) {
                  if (value.isEmpty) {
                    return 'Please enter some text';
                  }
                  return null;
                },
              ),
            )),
        PlayerGrid(_players)
      ])),
      bottomNavigationBar: CustomBottomNavigationBar(1),
    );
  }
}

它包含一个 ListView,ListView 中的一项是另一个小部件PlayerGrid,代码如下:

class PlayerGrid extends StatefulWidget {
  List<Player> players;
  PlayerGrid(this.players);
  @override
  _PlayerGridState createState() => _PlayerGridState();
}

class _PlayerGridState extends State<PlayerGrid> {
  List<Player> _players;
  @override
  void initState() {
    super.initState();
    _players = this.widget.players;
  }

  @override
  Widget build(BuildContext context) {
    print(context);
    return GridView.count(
      physics: NeverScrollableScrollPhysics(),
      padding: EdgeInsets.all(5),
      crossAxisCount: 3,
      primary: false,
      crossAxisSpacing: 0,
      mainAxisSpacing: 0,
      childAspectRatio: 0.7,
      shrinkWrap: true,
      children: <Widget>[for (var player in _players) Avatar(player)],
    );
  }
}

现在,在第一个小部件中,我更新了表单提交时的状态 _players。但是,此更新状态不会反映在子小部件PlayerGrid 中。我的代码有什么问题?

编辑:

发布更新的代码。

玩家:

class Players extends StatefulWidget {
  List<Player> players;
  Players(this.players);
  static const pageName = 'Players';
  static const routeName = '/Players';
  @override
  _PlayersState createState() => _PlayersState(this.players);
}

class _PlayersState extends State<Players> {
  List<Player> _players;
  _PlayersState(List<Player> players) {
    _players = players;
  }

  final _formKey = GlobalKey<FormState>();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: CustomAppBar(loggedInPlayer.balance),
      body: SafeArea(
          child: ListView(children: <Widget>[
        Container(
            padding: EdgeInsets.only(left: 10, right: 10, top: 10),
            child: Form(
              key: _formKey,
              child: TextFormField(
                onFieldSubmitted: (name) {
                  setState(() {
                    var filteredPlayers = this._players.where((x) =>
                        x.name.toLowerCase().contains(name.toLowerCase()));
                    this._players = filteredPlayers;
                  });
                },
                decoration: InputDecoration(
                  fillColor: Colors.white,
                  hintText: 'Search a player by name',
                  contentPadding: EdgeInsets.all(10),
                  border: OutlineInputBorder(),
                ),
                // The validator receives the text that the user has entered.
                validator: (value) {
                  if (value.isEmpty) {
                    return 'Please enter some text';
                  }
                  return null;
                },
              ),
            )),
        PlayerGrid(this._players)
      ])),
      bottomNavigationBar: CustomBottomNavigationBar(1),
    );
  }
}

PlayerGrid:

class PlayerGrid extends StatelessWidget {
  List<Player> players;
  PlayerGrid(this.players);
  @override
  @override
  Widget build(BuildContext context) {
    return GridView.count(
      physics: NeverScrollableScrollPhysics(),
      padding: EdgeInsets.all(5),
      crossAxisCount: 3,
      primary: false,
      crossAxisSpacing: 0,
      mainAxisSpacing: 0,
      childAspectRatio: 0.7,
      shrinkWrap: true,
      children: <Widget>[for (var player in this.players) Avatar(player)],
    );
  }
}

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    使用TextEditingController()TextFormField 获取文本。

    例子:

    class _PlayersState extends State<Players> {
      var _searchController = TextEditingController();
      List<Player> _players = [];
    
      _search() {
        {
          if (_formKey.currentState.validate()) {
            _players.clear();
            setState(() {
              var filteredPlayers = widget.players.where((Player x) => x.name
                  .toLowerCase()
                  .contains(_searchController.text.toLowerCase()));
              _players.addAll(filteredPlayers);
            });
          }
        }
      }
    
      final _formKey = GlobalKey<FormState>();
      @override
      Widget build(BuildContext context) {
        // var _players = widget.players;
        return Scaffold(
          // appBar: CustomAppBar(loggedInPlayer.balance),
          body: SafeArea(
              child: ListView(children: <Widget>[
            Container(
                padding: EdgeInsets.only(left: 10, right: 10, top: 10),
                child: Form(
                  key: _formKey,
                  // Create search box
                  child: Card(
                    child: new ListTile(
                      leading: IconButton(
                        icon: new Icon(Icons.search),
                        onPressed: _search,
                      ),
                      title: new TextFormField(
                        textInputAction: TextInputAction.done,
                        onFieldSubmitted: (_) {
                          _search();
                        },
                        controller: _searchController,
                        decoration: new InputDecoration(
                            hintText: 'Search', border: InputBorder.none),
                        // onChanged: onSearchTextChanged,
                      ),
                      trailing: new IconButton(
                        icon: new Icon(Icons.cancel),
                        onPressed: () {
                          _searchController.clear();
                          // onSearchTextChanged('');
                        },
                      ),
                    ),
                  ),
                )),
            PlayerGrid(_players)
          ])),
        );
      }
    }
    

    【讨论】:

    • 有没有办法在不添加额外凸起按钮的情况下做到这一点。我希望在键盘提交时重新加载列表。
    • 最常用的方法(我认为)是创建一个搜索栏。您还可以使用 TextInputAction.done 等键盘操作。检查更新的答案
    • 问题是我试图将Iterable 分配给状态变量而不是List
    • @NimishDavidMathew 映射,其中返回 Iterable 而不是 dart 中的 List。你说的对。要转换 Iterable,您需要使用 .toList() end of statement.
    【解决方案2】:

    .where() 函数返回一个Iterable&lt;Player&gt;。在将其分配给状态变量_players之前将其转换为List&lt;Player&gt;

    setState(() {
        _players = players
        .where((x) => x.name.toLowerCase().contains(name.toLowerCase())).toList();
    });
    

    【讨论】:

      猜你喜欢
      • 2021-07-25
      • 1970-01-01
      • 1970-01-01
      • 2019-06-26
      • 2021-06-11
      • 2021-01-08
      • 2018-09-01
      • 2021-06-29
      • 1970-01-01
      相关资源
      最近更新 更多