【问题标题】:Change CheckBox value with custom class property使用自定义类属性更改 CheckBox 值
【发布时间】:2018-08-19 08:16:45
【问题描述】:

这是我第一次在这里发帖,如果我做错了,我深表歉意。

我创建了一个带有布尔字段的自定义类来控制 CheckBox 状态/值:

class CustomModel {
static const TITLE_KEY = 'title';

  String id;
  String title;
  bool isChecked = false;

  void setIsChecked(bool isChecked) {
    this.isChecked = isChecked;
  }

  bool getIsChecked() {
    return isChecked;
  }

  CustomModel(Map<String, dynamic> ex) {
    title = ex[TITLE_KEY];
  }
}

在我的 CheckBox 小部件中:

return new ExpansionTile(
                title: const Text('Title'),
                backgroundColor: Colors.grey[100],
                children: snapshot.data.documents
                    .map((DocumentSnapshot document) {
                  CustomModel ex = new CustomModel(document.data);
                  return new ListTile(
                    title: new Text(ex.title),
                    trailing: new Checkbox(
                        value: ex.getIsChecked(),
                        onChanged: (bool value) {
                          setState(() {                             
                            ex.setIsChecked(value);
                          });
                        }),
                  );
                }).toList());
          }),

CheckBox 在单击时不会改变(有点闪烁)。日志显示 CheckBox 是“false”然后是“true”,但是如果我再次单击同一个 CheckBox,日志会显示“false”然后是“true”,所以它似乎没有更新该字段。

当我在 Java 中执行此操作时,我不必将值设置为“isChecked”,但如果我不这样做,Flutter 会抛出错误。

I/flutter ( 6408): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════

I/flutter (6408):在构建 StreamBuilder(dirty, state: 我/颤振(6408):_StreamBuilderBaseState>#0512c): I/flutter(6408):'package:flutter/src/material/checkbox.dart':断言失败:第 63 行:'tristate ||价值!= I/flutter (6408): null': 不正确。

提前谢谢你!

【问题讨论】:

  • 我会更深入地研究 setState 函数。我不熟悉颤振;但是,我确实知道在 ReactJS 中,有一个功能似乎以类似的方式工作。为什么这很重要?在 ReactJS 中,setState 函数可能会一起批处理调用以提高性能。这也意味着调用可能不会同步工作。看flutter的setState看起来差不多,也可能是批量调用。
  • Tyler - 谢谢,我正在研究 setState 函数。我没有使用 React 的经验,你能解释一下批量调用和同步调用吗?
  • 这是一个通用主题。基本上,同步调用意味着调用 1 将在调用 2 之前处理。调用 2 在调用 3 之前,等等。批处理调用将调用调用 1、调用 2 和调用 3,并在实际需要时稍后处理它们或在其他一些条件下。它不能保证是同步的,因此它可以处理各种顺序的调用。例如...调用 2,调用 3,然后调用 1。
  • 你不需要有 React 的经验。我想说的是 React 有一个 setState 函数,它可以批量调用。这意味着调用可能不是同步的。查看您的颤振的setState 示例,它们似乎很相似。所以flutter的setState也可能会批量调用或者做一些可能会给初学者带来问题的事情——就像React一样。本质上,您只是想详细了解setState 如何在 Flutter 中工作,以及是否有任何应该避免的不良做法和应该遵循的良好做法。
  • 泰勒 - 谢谢你的解释。我更改了代码,因此它修改了 Firestore 中的一个字段,并根据 setState 函数进行了相应的更新。你知道我的 getter 和 setter 格式是否正确吗?我不想让 Firestore 保留这些数据,因为我必须在之后将其清除。经过更多测试,看起来值在按下时变为“true”,然后立即从属性中提取“false”值。

标签: android mobile dart flutter


【解决方案1】:

我假设return new ExpansionTile(..); 在您的StatefulWidget 类的build() 方法中。所以当你调用setState()时,它会重新构建小部件,这意味着再次调用return new ExpansionTile(..);。由于您的 CustomModel ex = new CustomModel(document.data); 也将再次实例化,并且 isChecked 届时将是错误的。所以解决方案是将你所有的构建CustomModel 列表从firestore 放到initState() 中。

就是这个想法,(可能有一些语法错误,因为我直接写在这里)。

class MyWidget extends StatefulWidget {
   State createState() => new MyWidgetState();  } 

class MyWidgetState extends State<MyWidget> {
  List<CustomModel> customModels = []; 
  @override 
  initState() {
     //use listener to fetch data  
     Firestore.instance.collection("name").snapshots.listen((snapshot) {
        for (var doc in snapshot.documents) {
            CustomModel ex = new CustomModel(fieldname: doc['fieldname]);
            customModels.add(ex); 
        }

       }
    }

   @override
   Widget build(BuildContext) {
     return new ExpansionTile(
                title: const Text('Title'),
                backgroundColor: Colors.grey[100],
                children: customModels.map((CustomModel ex) {
                  return new ListTile(
                    title: new Text(ex.title),
                    trailing: new Checkbox(
                        value: ex.getIsChecked(),
                        onChanged: (bool value) {
                          setState(() {                             
                            ex.setIsChecked(value);
                          });
                        }),
                  );
                }).toList());
          }),
     }    

}

【讨论】:

  • Grep - 非常感谢您的解释和代码 sn-p。我了解需要在 initState 中重新创建 ExpansionTile 小部件,但我不明白如何创建它或如何在 initState 函数中获取 Firestore 的快照。我目前正在使用 StreamBuilder 拍摄快照并将流经小部件树的数据向下拉到 ExpansionTile 小部件。我需要创建一个自定义的 ExpansionTile 小部件吗?喜欢 Stateful 和 State 类并引用树中的自定义小部件?
  • @r3ck3z57 我已经更新了我的答案,您可以使用Firestore.instance.collection('name').snapshot.listen((snapshot) {.. }) 而不必使用StreamBuilder
  • 谢谢!!感谢大家的帮助!我更新了代码,它运行良好。
猜你喜欢
  • 1970-01-01
  • 2017-07-27
  • 2014-06-08
  • 2015-03-06
  • 1970-01-01
  • 1970-01-01
  • 2015-08-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多