首页 > 解决方案 > 当 AlertDialog 中的复选框选中或未选中时,Flutter 更新 Reorderable ListView

问题描述

我目前正在开发一个应该可以在 Android 和 IOS 上运行的 Flutter 移动应用程序。我遇到的问题是关于 ListView 和更新它。

我知道我在很多事情上都做错了,但我正在学习,我想好好学习。因此,如果您有任何意见,请提供有关代码的提示:)

基本上这就是它的作用:主要玩家将通过一个 AlertDialog 选择谁将在游戏中与他一起玩,AlertDialog 里面有一个 CheckboxList,每次他选择一个玩家时,它都会更新一个名为 choosenPlayers 的列表,其中选择了所有 Player 对象在里面。

然后我想要做的是显示所有选定玩家的列表(一个可重新排序的列表以更改玩家的顺序)并在每次更新选择玩家列表时更新它。

我设法显示了这些播放器,但我必须通过进入抽屉菜单并单击页面链接来重新加载页面以查看添加的播放器。

我为我的玩家可重新排序列表使用有状态小部件,并将玩家列表传递给父级(我知道这不是正确的方法):

import 'package:flutter/material.dart';
import 'package:mollky/models/player.dart';

class ChoosenPlayers extends StatefulWidget {
  _ChoosenPlayersState _choosenPlayersState = _ChoosenPlayersState();
  List<Player> choosenPlayers = [];
  ChoosenPlayers({Key key, this.choosenPlayers}) : super(key: key);

  @override
  _ChoosenPlayersState createState() => _choosenPlayersState;
}

class _ChoosenPlayersState extends State<ChoosenPlayers> {
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return ReorderableListView(
      onReorder: onReorder,
      children: getListItems(),
    );
  }

  List<ListTile> getListItems() => widget.choosenPlayers
      .asMap()
      .map((i, item) => MapEntry(i, buildTenableListTile(item, i)))
      .values
      .toList();

  ListTile buildTenableListTile(Player item, int index) {
    return ListTile(
      key: ValueKey(item.id),
      title: Text(item.nickname + " " + item.name),
      leading: Text("#${index + 1}"),
    );
  }

  void onReorder(int oldIndex, int newIndex) {
    if (newIndex > oldIndex) {
      newIndex -= 1;
    }

    setState(() {
      Player reOrderedPlayer = widget.choosenPlayers[oldIndex];

      widget.choosenPlayers.removeAt(oldIndex);
      widget.choosenPlayers.insert(newIndex, reOrderedPlayer);
    });
  }
}

这是显示可重新排序列表和显示 AlertDialog 的主页的代码。抱歉,无法用 Dart 格式化,不要运行明显被剪断的代码 xD

class NewGame extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => NewGameState();
}

class NewGameState extends State<NewGame> {
  List<Player> players = [];

  NewGameState() {
    this.players.add(
        Player(id: 0, name: "Dupont", nickname: "julien", picture: "test"));
    this
        .players
        .add(Player(id: 1, name: "Dpont", nickname: "julien", picture: "test"));
    this
        .players
        .add(Player(id: 2, name: "Dunt", nickname: "juen", picture: "test"));
  }

  static List<Player> _choosenPlayers = [];
  ChoosenPlayers choosenPlayersObject = ChoosenPlayers(
    choosenPlayers: _choosenPlayers,
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        drawer: DrawerWidget(),
        appBar: AppBar(title: Text("Nouvelle partie")),
        body: Column(children: <Widget>[
          Card(
              child: ListTile(
                  leading: Icon(Icons.people),
                  title: Text("Choisissez les joueurs"),
                  onTap: () {
                    showDialog(
                        context: context,
                        builder: (BuildContext context) {
                          return AlertDialog(
                              title: Text("Les joueurs existants"),
                              content:
                                  Stack(overflow: Overflow.visible, children: <
                                      Widget>[
                                Positioned(
                                  right: -40.0,
                                  top: -40.0,
                                  child: InkResponse(
                                    onTap: () {
                                      Navigator.of(context).pop();
                                    },
                                    child: CircleAvatar(
                                      child: Icon(Icons.close),
                                      backgroundColor: Colors.lightBlue,
                                    ),
                                  ),
                                ),
                                Positioned(
                                  child: StatefulBuilder(
                                    builder: (BuildContext context,
                                        StateSetter setState) {
                                      return Container(
                                        width: 350.0,
                                        height: 150.0,
                                        child: ListView.builder(
                                            itemCount: players.length,
                                            itemBuilder:
                                                (context, playerIndex) {
                                              return CheckboxListTile(
                                                title: Text(players[playerIndex]
                                                        .nickname +
                                                    " " +
                                                    players[playerIndex].name),
                                                value: _choosenPlayers.contains(
                                                    players[playerIndex]),
                                                onChanged: (bool value) {
                                                  if (!_choosenPlayers.contains(
                                                      players[playerIndex])) {
                                                    _choosenPlayers.add(
                                                        players[playerIndex]);
                                                    setState(() {});
                                                  } else {
                                                    _choosenPlayers.remove(
                                                        players[playerIndex]);
                                                    setState(() {});
                                                  }
                                                },
                                                secondary: const Icon(
                                                    Icons.hourglass_empty),
                                              );
                                            }),
                                      );
                                    },
                                  ),
                                ),
                              ]));
                        });
                  })),
          Container(
            width: 350.0,
            height: 150.0,
            child: choosenPlayersObject,
          ),
        ]));
  }
}

我在论坛上没有看到关于更新列表而不触发像 onRefresh 这样的回调,这不是我想要的。

这是一个真正的噩梦xD。抱歉,法语单词顺便说一句,如果需要我可以翻译,但它们并不重要,简单的文字。

这是列表和警报对话框的两个屏幕截图:

在此处输入图像描述

在此处输入图像描述

先感谢您 :)

标签: androidioslistviewflutterdart

解决方案


父小部件的状态未更新。这就是为什么,即使付款人已添加到列表中。但未显示在父小部件中。您调用的setState仅更新StatefulBuilder的状态,而不是NewGame的状态。查看下面的代码。

演示

  import 'package:flutter/material.dart';

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

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

class NewGameScreen extends StatefulWidget {
  @override
  _NewGameScreenState createState() => _NewGameScreenState();
}

class _NewGameScreenState extends State<NewGameScreen> {
  List<Player> _availablePlayers = [];
  List<Player> _selectedPlayers = [];

  @override
  void initState() {
    super.initState();
    _availablePlayers = [
      Player(id: 0, name: "Ross", nickname: "Geller", picture: "test"),
      Player(id: 1, name: "Rachel", nickname: "Green", picture: "test"),
      Player(id: 2, name: "Chandler", nickname: "Bing", picture: "test"),
    ];
  }

  _selectPlayer() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text("Existing players"),
          content: Stack(
            overflow: Overflow.visible,
            children: <Widget>[
              Positioned(
                right: -40.0,
                top: -40.0,
                child: InkResponse(
                  onTap: () {
                    Navigator.of(context).pop();
                  },
                  child: CircleAvatar(
                    child: Icon(Icons.close),
                    backgroundColor: Colors.lightBlue,
                  ),
                ),
              ),
              StatefulBuilder(
                builder: (BuildContext context, StateSetter alertState) {
                  return Container(
                    width: 350.0,
                    height: 150.0,
                    child: ListView.builder(
                      itemCount: _availablePlayers.length,
                      itemBuilder: (context, playerIndex) {
                        return CheckboxListTile(
                          title:
                              Text(_availablePlayers[playerIndex].nickname + " " + _availablePlayers[playerIndex].name),
                          value: _selectedPlayers.contains(_availablePlayers[playerIndex]),
                          onChanged: (bool value) {
                            if (_selectedPlayers.contains(_availablePlayers[playerIndex])) {
                              _selectedPlayers.remove(_availablePlayers[playerIndex]);
                            } else {
                              _selectedPlayers.add(_availablePlayers[playerIndex]);
                            }
                            setState(() {});//ALSO UPDATE THE PARENT STATE
                            alertState(() {});
                          },
                          secondary: const Icon(Icons.hourglass_empty),
                        );
                      },
                    ),
                  );
                },
              ),
            ],
          ),
        );
      },
    );
  }

  _onReorder(int oldIndex, int newIndex) {
    if (newIndex > oldIndex) {
      newIndex -= 1;
    }
    print('oldIndex:$oldIndex');
    print('newIndex:$newIndex');
    setState(() {
      Player player = _selectedPlayers[newIndex];
      _selectedPlayers[newIndex] = _selectedPlayers[oldIndex];
      _selectedPlayers[oldIndex] = player;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("New Game")),
      body: Column(
        children: <Widget>[
          Card(
            child: ListTile(
              leading: Icon(Icons.people),
              title: Text("Choose players"),
              onTap: _selectPlayer,
            ),
          ),
          Flexible(
            child: ReorderableListView(
              onReorder: _onReorder,
              children: _selectedPlayers.map((player) {
                return ListTile(
                  key: ValueKey(player.id),
                  title: Text(player.nickname + " " + player.name),
                  leading: Text("#${_selectedPlayers.indexOf(player) + 1}"),
                );
              }).toList(),
            ),
          ),
        ],
      ),
    );
  }
}

class Player {
  int id;
  String name;
  String nickname;
  String picture;

  Player({this.id, this.name, this.nickname, this.picture});
}

希望能帮助到你 :)


推荐阅读