首页 > 解决方案 > Flutter listview:移除一个Item时,下一个继承一些属性

问题描述

我正在开发一个项目,其中有一个名为 AlarmCard 的自定义小部件的 ListView,每个小部件都填充了警报对象的信息。AlarmCard 有两个布尔属性:Expanded 和 Loading,这是主要代码:

class _AlarmCardState extends State<AlarmCard>{
  bool _expanded = false;
  bool _loading = false;
  static const double iconSize = 28.0;
  static const Color iconColor = Colors.black87;
  static const TextStyle fieldTextStyle = TextStyle(
    fontSize: 16.0,
    fontWeight: FontWeight.w400,
    color: Color.fromRGBO(0, 0, 0, 0.6),
  );

  static const TextStyle clearFieldTextStyle = TextStyle(
    fontSize: 16.0,
    fontWeight: FontWeight.w400,
    color: Color.fromRGBO(0, 0, 0, 0.2),
  );

  @override
  Widget build(BuildContext context) {
    TextStyle timeTextStyle = TextStyle(
      fontSize: 54.0,
      fontWeight: FontWeight.w400,
      color: Colors.black54,
    );

    Widget card = Card(
      child: Column(
        children: <Widget>[
          Opacity(
            opacity: _loading ? 1.0 : 0.0,
            child: Container(
              height: 3.0,
              child: ClipRRect(
                child: LinearProgressIndicator(),
                borderRadius: BorderRadius.only(
                  topRight: Radius.circular(3.0),
                  topLeft: Radius.circular(3.0),
                ),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.fromLTRB(12.0, 8.0, 12.0, 8.0),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  mainAxisSize: MainAxisSize.max,
                  children: <Widget>[
                    Padding(
                      padding: const EdgeInsets.only(top: 6.0, bottom: 8.0),
                      child: InkWell(
                          onTap: () => _selectTime(context),
                          child: Text(widget.alarm.timeString, style: timeTextStyle)
                      ),
                    ),
                    Switch(value: widget.alarm.enabled, onChanged: _onAlarmEnabledChange),
                  ],
                ),
                AnimatedCrossFade(
                  firstChild: _getContractedBottom(),
                  secondChild: _getExpandedBottom(),
                  duration: Duration(milliseconds: 200),
                  crossFadeState: _expanded ? CrossFadeState.showSecond : CrossFadeState.showFirst,
                )
              ],
            ),
          ),
        ],
      ),
    );

    return _loading ?
      Opacity(
        opacity: 0.6,
        child: IgnorePointer(
          child: card
        ),
      )
      : card;
      }
...
}

当然,还有一些自定义小部件,例如 DayToggle,以及返回小部件的 _getContractedBottom() 和 _getExpandedBottom() 方法。一旦我们定义了依赖 _expanded 和 _loading 的 AlarmCard 构建方法,我们使用final List<Alarm> alarmList如下方式构建 ListView:

ListView.builder(
  itemCount: alarmList.length,
  itemBuilder: (BuildContext context, int i) {
    Alarm alarm = alarmList[i];
    return AlarmCard(
      alarm: alarm,
      ringtones: ringtoneList,
      onAlarmUpdated: () => true,
      onAlarmDeleted: () {
        setState(() {
          alarmList.remove(alarm);
        });
        return true;
      }
    );
  },
)

因此,ListView 完美地工作,并且每个项目都按原样显示,它可以扩展和更新(以便 _loading 变为真)。删除项目时会出现问题。

想象一下,alarmList 有 8 个项目,它们都显示在屏幕上,我们只展开和删除第 6 个项目。当我们按下Delete的那一刻,AlarmCard变成Loading状态,然后被删除,但是一旦从ListView中移除,第7项“继承”了_expanded和_loading属性,所以它显示了与它的alarm对应的正确信息,但它被扩展和加载,而它不应该。

有人知道问题可能出在哪里吗?我一直在搜索多个网站和 stackoverflow 帖子,但找不到这个问题。非常感谢!

标签: androidioslistviewflutterflutter-layout

解决方案


正如@javired98 所说,问题很关键。那个视频对我有帮助。但请记住,如果您有小部件列表,则当您将其添加到未在小部件类中定义的列表时,密钥必须传递给小部件。

          imageList.add(ImageElement(
            key:ValueKey(imageCounter),
            id: ...,
            imgURL: ...,
              .
              .
              . 
           ));

推荐阅读