检查 ListView 中的一个 CheckBox 使用 Flutter 来检查所有其余的 CheckBox

Posted

技术标签:

【中文标题】检查 ListView 中的一个 CheckBox 使用 Flutter 来检查所有其余的 CheckBox【英文标题】:Checking one CheckBox in a ListView checks all of the rest using Flutter 【发布时间】:2020-09-07 15:00:33 【问题描述】:

我对 Flutter 和 *** 完全陌生。事实上,这是我的第一个问题,所以如果我完全没有提出这个问题,请原谅我。我正在尝试制作一个简单的 Flutter 应用程序,它提供问题的 ListView 和每个问题旁边的复选框。然后用户可以选择他们想要回答的问题。我的问题是,当用户选中任何复选框时,所有复选框都会被选中,反之亦然。问题本身是从无后端数据库中检索的。下面的代码是我到目前为止所拥有的。任何人都可以为我提供任何帮助,我将不胜感激。

import 'package:flutter/material.dart';

class Questions extends StatefulWidget 
  final List<Map> questionList;

  Questions(this.questionList);

  @override
  _QuestionsState createState() => _QuestionsState();


class _QuestionsState extends State<Questions> 
  bool _questionSelected = true;

  Widget _buildQuestionItem(BuildContext context, int index) 
    return ListTile(
      title: Text(widget.questionList[index]['question']),
      trailing: Checkbox(
        value: _questionSelected,
        onChanged: (bool val)
          setState(() 
            _questionSelected = val;
          );
        ,
      ),
    );
  

  @override
  Widget build(BuildContext context) 
    return ListView.builder(
      padding: EdgeInsets.all(10),
      itemBuilder: _buildQuestionItem,
      itemCount: widget.questionList.length,
    );
  

更新:

感谢 Mohammed Ashab Uddin 的建议我觉得我已经接近让这个东西工作但我仍然收到错误

"RangeError(index):无效值:有效值范围为空:0"

我想我应该在我设置 questionList 值的地方发布 main.dart 代码,也许它是导致此错误的代码执行顺序,所以请在下面找到我的 main.dart 代码,希望它会有所帮助解决这个问题。

import 'package:flutter/material.dart';
import 'package:backendless_sdk/backendless_sdk.dart';
import 'package:flutter/rendering.dart';

import 'questions.dart';

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

class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'RT Database Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Questions'),
    );
  


class MyHomePage extends StatefulWidget 
  MyHomePage(Key key, this.title) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();


class _MyHomePageState extends State 
  static const String API_HOST = "https://api.backendless.com";
  static const String APP_ID = "<APP_ID>";
  static const String android_APP_KEY = "<ANDROID_APP_KEY>";
  static const String ios_APP_KEY = "<IOS_APP_KEY>";

  IDataStore<Map> questionsStore = Backendless.data.of('Questions');
  List<Map> questionsList = [];
  var _questionSelected = false;

  @override
  void initState() 
    super.initState();
    _initBackendless();
    _enableRealTime();
    getQuestions();
  

  void _initBackendless() 
    Backendless.setUrl(API_HOST);
    Backendless.initApp(APP_ID, ANDROID_APP_KEY, IOS_APP_KEY);
  

  void _enableRealTime() 
    EventHandler<Map> rtHandlers = questionsStore.rt();

    rtHandlers.addCreateListener((question) 
      setState(() 
        questionsList = List.from(questionsList);
        questionsList.add(question);
      );
    );

    rtHandlers.addUpdateListener((question) 
      setState(() 
        questionsList = List.from(questionsList
            .map((m) => m['objectId'] == question['objectId'] ? question : m));
      );
    );

    rtHandlers.addDeleteListener((question) 
      setState(() 
        questionsList = List.from(questionsList);
        questionsList.removeWhere((m) => m['objectId'] == question['objectId']);
      );
    );
  

  void _selectQuestion(bool newValue) 
    setState(() 
      _questionSelected = newValue;
    );
  

  void getQuestions() 
    DataQueryBuilder queryBuilder = DataQueryBuilder()
      ..pageSize = 100
      ..sortBy = ['created'];

    questionsStore
        .find(queryBuilder)
        .then((response) => setState(() => questionsList = response));
  

  @override
  Widget build(BuildContext context) 

    return Scaffold(
      appBar: AppBar(
        title: Text("My Life History"),
      ),
      body: FractionallySizedBox(
        heightFactor: 0.5,
        child: Questions(questionsList),
      ),
    );
  

【问题讨论】:

【参考方案1】:

变量_questionSelected 是一个全局变量。所有复选框小部件都使用此变量作为值。因此,当onChanged()函数上的变量发生变化时,所有的值也会变为_questionSelected的值。

在这种情况下,您需要跟踪复选框小部件的所有值。因此,您应该使用数组而不是单个变量。

我通常做的是,创建一个仅包含所选元素的新列表。 如果一个元素没有被选中,则删除它,如果它被选中,则添加一个元素。

//generate a list of false values with the length of questionList
List<bool> _questionSelected;

initState()
   _questionSelected = List<bool>.filled(questionList.length, false, growable: true);
   super.initState();


  Widget _buildQuestionItem(BuildContext context, int index) 
    return ListTile(
      title: Text(widget.questionList[index]['question']),
      trailing: Checkbox(
        value: _questionSelected[index],
        onChanged: (bool val)
          setState(() 
            _questionSelected[index] = val;
          );
        ,
      ),
    );
  

【讨论】:

当我按照上面的建议编辑代码时,填充方法的长度变量出现错误。它说只有静态成员可以在初始化程序中访问。我尝试阅读该错误的 dart 诊断消息,但无法理解它的含义以及它如何应用于我的代码。 我忘了说你需要在initState()中初始化_questionSelected的值。我再次编辑了我的代码。 我收到一个 RangeError,我觉得这可能是因为代码执行的顺序。我忘记在我的原始帖子中包含调用 questions.dart 代码的 main.dart 代码。我编辑了帖子以包含该代码,希望它可以给出 RangeError 来源的一些指示。我自己想不通。我应该补充一点,如果我在代码的填充方法中用数字 3 替换“questionList.length”,它就可以工作。我感觉在 questions.dart 被调用的时候,questionList 没有被初始化。这就是为什么我还发布了调用 questions.dart 的 main.dart

以上是关于检查 ListView 中的一个 CheckBox 使用 Flutter 来检查所有其余的 CheckBox的主要内容,如果未能解决你的问题,请参考以下文章

listView中带有复选框的自定义布局:当我删除一行时,如果选中它(checkBox = true),则下一行将获得检查

android中如何获得listview中的checkbox的值?

Android:将数据库中的数据绑定到 ListView 中的 CheckBox?

Android中ListView结合CheckBox判断选中项

listView 中获取不到checkBox的 那么属性?

Gridview, ListView中的item含有checkbox,setOnItemClickListener方法失效的问题