【问题标题】:Flutter ListView widgets resets icon when scrolling items out of screenFlutter ListView 小部件在将项目滚动出屏幕时重置图标
【发布时间】:2019-10-20 16:25:07
【问题描述】:

我有一个 ListView,其中包含自定义的 statefull 小部件作为项目。 这些项目有一个 onTap 事件,可以将图标从 check_box_outline_blank 切换到 check_box,反之亦然。

但是,当我在列表中选择一个项目并向下滚动并再次备份时,该项目已将图标从 check_box 重置为 check_box_outline_blank。

如何防止这种情况发生?

            new Expanded(
                child: ListView.builder(
                  itemCount: _list.length,
                  itemBuilder: (BuildContext context, int index) {
                    return listTile(_pveList[index], index)
                  },
                )
            )

 //Adds extra space(height:100) after the last tile
 StatefulWidget listTile(String text, int index){
    return (index < _pveList.length - 1)?new SelectableListItem(text: text,
      onTap: (){
        _handleOnTap(text);
      },
    ): new Column(
      children: <Widget>[
        new SelectableListItem(text: text,
          onTap: (){
            _handleOnTap(text);
          },
        ),
        SizedBox(
          height: 100,
        )
      ],
    );
  }

磁贴小部件(SelectableListItem):

import 'package:flutter/material.dart';

class SelectableListItem extends StatefulWidget {
  SelectableListItem({Key key, this.text, this.onTap})
      : super(key: key);
  final String text;
  final GestureTapCallback onTap;

  @override
  _SelectableListItemState createState() => _SelectableListItemState();
}

class _SelectableListItemState extends State<SelectableListItem> {

  bool isSelected = false;
  Icon _checked = new Icon(Icons.check_box_outline_blank);

  handleOnTap() {
    isSelected = !isSelected;
    if (isSelected) {
      setState(() {
        _checked = new Icon(Icons.check_box);
      });
    } else {
      setState(() {
        _checked = new Icon(Icons.check_box_outline_blank);
      });
    }
    return widget.onTap();
  }

  @override
  Widget build(context) {
    // Pass the text down to another widget
    return new GestureDetector(
      behavior: HitTestBehavior.translucent,
      onTap: () => handleOnTap(),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          new Padding(
            padding: EdgeInsets.all(22),
            child: new Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                new Text(widget.text, style: TextStyle(fontSize: 18)),
                _checked
              ],
            ),
          ),
          new Container(
            width: double.infinity,
            height: 1,
            color: Color(0x1a222222),
          )
        ],
      ),
    );
  }
}

【问题讨论】:

  • 请发布您的ListView 和有状态小部件类的一些代码。
  • @George 我已经用代码示例更新了问题

标签: flutter flutter-layout


【解决方案1】:

更新

我相信 OP 想要实现一个标准的 Checkbox,除了标签文本。

CheckboxListTile 小部件提供了这样的功能。

使用示例:

bool selected = false;

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Column(children: <Widget>[

      CheckboxListTile(
        onChanged: (val) {
          setState(() {
            selected = !selected;
          });
        },
        value: selected,
        title: Text("Test"),
      )

    ]),
  );
}

如果您想让复选框位于屏幕左侧 - 相应地设置 controlAffinity 属性:

CheckboxListTile(
  // ...,
  controlAffinity: ListTileControlAffinity.leading,
)

原答案

#1

您不应该使用函数来构建小部件树。

更多详情请见this answer

#2

我建议使用ValueNotifier,在SelectableListItem 类中声明。

它允许您更改StatefulWidget 中变量的值,而不会出现非最终变量的通常警告。

ValueNotifier 内部的值也被保留,就像在 StatefulWidget 类中声明的任何其他变量一样。

例如

class SelectableListItem extends StatefulWidget {
  // ...
  final ValueNotifier<bool> isSelected = ValueNotifier<bool>(false);
  // ...
}

class _SelectableListItemState extends State<SelectableListItem> {

  handleOnTap() {
    setState(() {
      widget.isSelected.value = !widget.isSelected.value;
    });
    return widget.onTap();
  }

  // ... build() { ...
  Row(
    mainAxisAlignment: MainAxisAlignment.spaceBetween,
    children: <Widget>[
      Text(widget.text, style: TextStyle(fontSize: 18)),
      Icon(widget.isSelected.value ? Icons.check_box : Icons.check_box_outline_blank),
    ]
  ),
  // ... } ...

}

ValueNotifier&lt;bool&gt; 还消除了将图标小部件存储在单独变量中的需要。相反,您可以在内联布尔条件中使用它,就像代码中显示的那样。

PS:我没有测试代码,但是一般说明是有效的。让我知道这是否有帮助。

【讨论】:

  • 感谢您的详细解答!我将在今天晚些时候测试 ValueNotifier ?
  • widget.isSelected.value 使用 handleOnTap() 成功更新,但 Icon 没有改变...
  • 让我尝试运行我的代码,也许我将能够复制这种行为......
  • @Christer 你想实现一个简单的复选框行为吗?有CheckboxListTile 小部件。如果是这种情况,请告诉我,我会更新我的答案。
  • 是的,没错?我不知道存在 CheckboxTile 小部件。
猜你喜欢
  • 1970-01-01
  • 2016-04-04
  • 1970-01-01
  • 2020-02-18
  • 1970-01-01
  • 2011-07-04
  • 2021-01-14
  • 1970-01-01
  • 2018-08-15
相关资源
最近更新 更多