具有Bloc模式的复选框管理-完整代码

时间:2019-02-07 22:59:23

标签: flutter

我正在尝试使用块模式来管理我的复选框集。团体只需要存储是否选中该复选框即可。

下面是可以运行以模拟正在发生的事情的代码。

我得到的(错误)结果是,当您更新复选框时,数据无法正确呈现。

checkbox teste stackoverflow

日志

First Click in Checkbox 1
I/flutter ( 6239): newMapCheckbox: {1: true}
I/flutter ( 6239): _mapCheckbox: {1: true, 2: false, 3: false}

Second Click in Checkbox 1
I/flutter ( 6239): newMapCheckbox: {1: null}
I/flutter ( 6239): _mapCheckbox: {1: null, 2: false, 3: false}

代码

import 'package:flutter/material.dart';
import 'dart:collection';

import 'package:rxdart/rxdart.dart';

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

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

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    ApplicationBloc _bloc = new ApplicationBloc();

    return Scaffold(
      appBar: AppBar(
        title: Text('Checkbox Test'),
      ),
      body: StreamBuilder(
        stream: _bloc.listItemModel,
        builder:
            (BuildContext context, AsyncSnapshot<List<ItemModel>> snapshot) {
          if (!snapshot.hasData) {
            return CircularProgressIndicator();
          }
          List<ItemModel> listItemModel = snapshot.data;

          return ListView.builder(
            shrinkWrap: true,
            itemCount: listItemModel.length,
            itemBuilder: (context, index) {
              ItemModel itemModel = listItemModel[index];
              return ListTile(
                leading: _checkbox(_bloc, itemModel.id),
                title: Text('${itemModel.name}'),
              );
            },
          );
        },
      ),
    );
  }

  _checkbox(ApplicationBloc _bloc, int idItemModel) {
    // This doesn't render like expected
    return StreamBuilder(
      stream: _bloc.checkboxController,
      builder: (BuildContext context, AsyncSnapshot<Map<int, bool>> snapshot) {
        if (snapshot.hasData) {
          return Checkbox(
            tristate: true,
            value: snapshot.data[idItemModel],
            onChanged: (value) => _bloc.setCheckbox(
                  <int, bool>{idItemModel: value},
                ),
          );
        } else
          return Container();
      },
    );
  }
}

class ItemModel {
  int id;
  String name;
  ItemModel(this.id, this.name);
}

class ApplicationBloc {
  // List Management
  BehaviorSubject<List<ItemModel>> listModelController =
      BehaviorSubject<List<ItemModel>>();
  Observable<List<ItemModel>> get listItemModel => listModelController.stream;

  // Checkbox Management - Item Model ID and checkbox value
  BehaviorSubject<Map<int, bool>> checkboxController =
      BehaviorSubject<Map<int, bool>>();
  Observable<Map<int, bool>> get mapModelCheckbox => checkboxController.stream;
  Function(Map<int, bool>) get setCheckbox => checkboxController.sink.add;

  List<ItemModel> _listItemModel = List<ItemModel>();
  Map<int, bool> _mapCheckbox = HashMap<int, bool>();

  ApplicationBloc() {
    // Initial data for list and map
    _listItemModel.add(ItemModel(1, 'Item Model 1'));
    _mapCheckbox[1] = false;
    _listItemModel.add(ItemModel(2, 'Item Model 2'));
    _mapCheckbox[2] = false;
    _listItemModel.add(ItemModel(3, 'Item Model 3'));
    _mapCheckbox[3] = false;

    // Insert initial data in controller
    listModelController.add(_listItemModel);
    checkboxController.add(_mapCheckbox);

    // Handler for checkbox state
    checkboxController.stream.listen(setCheckboxHandler);
  }

  setCheckboxHandler(Map<int, bool> newMapCheckbox) {
    // New checkbox value for the itemModel id
    int id = newMapCheckbox.entries.elementAt(0).key;
    bool check = newMapCheckbox.entries.elementAt(0).value;
    if (_mapCheckbox.containsKey(id)) {
      _mapCheckbox[id] = check;
    }
    print('-----------');
    print('newMapCheckbox: $newMapCheckbox');
    print('_mapCheckbox: $_mapCheckbox');
    print('-----------');
  }

  //dispose/close all the streams when we call dispose() method
  void dispose() {
    listModelController.close();
    checkboxController.close();
  }
}

1 个答案:

答案 0 :(得分:0)

对于您所需要的,您只应在复选框中管理两个状态。

以代码为基础,我们有这样的东西。

import 'package:flutter/material.dart';

import 'dart:collection';

import 'package:rxdart/rxdart.dart';

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

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

// model amenities.
class Item {
  int id;
  String title;
  Item({this.id, this.title});
  List<String> _amenities = [
    "Item Model 1",
    "Item Model 2",
    "Item Model 3",
  ];

  List<String> getAm(
      Map<int, bool> checkBoxes, Map<int, String> checkAmenities) {
    List<String> _am = [];

    for (var i = 0; i < checkBoxes.length; i++) {
      if (checkBoxes[i] != false) {
        print(i);
        print(checkAmenities[i]);
        _am.add(checkAmenities[i]);
      }
    }
    return _am;
  }

  List<Item> getItems() {
    List<Item> _items = [];
    for (var i = 0; i < _amenities.length; i++) {
      _items.add(Item(id: i, title: _amenities[i]));
    }
    return _items;
  }
}

class Demo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Item _item = Item();
    List<Item> checkBoxList = _item.getItems();
    AmenitiesBloc _bloc = new AmenitiesBloc();
    return new Scaffold(
      appBar: new AppBar(title: new Text('CheckboxListTile demo')),
      body: Container(
        height: 225.0,
        child: Card(child: grupCheck(checkBoxList, _bloc)),
      ),
    );
  }

  ListView grupCheck(List<Item> checkBoxList, AmenitiesBloc _bloc) {
    return new ListView.builder(
        itemCount: checkBoxList.length,
        itemBuilder: (BuildContext context, int index) {
          return new Container(
            padding: new EdgeInsets.all(0.0),
            child: new Column(
              children: <Widget>[
                StreamBuilder<Object>(
                    stream: _bloc.checkboxController,
                    builder: (context, snapshot) {
                      return new CheckboxListTile(
                        activeColor:
                            Colors.green, //Check is true color is green
                        dense: true, //font change
                        value: _bloc._mapCheckbox[index],
                        title: new Text(checkBoxList[index].title),
                        controlAffinity: ListTileControlAffinity
                            .leading, //Display check box first, remove this line checkbox display last
                        onChanged: (value) =>
                            _bloc.setCheckbox(<int, bool>{index: value}),
                      );
                    })
              ],
            ),
          );
        });
  }
}

// The bloc

class AmenitiesBloc {
  // Checkbox Management - Item Model ID and checkbox value
  BehaviorSubject<Map<int, bool>> checkboxController =
      BehaviorSubject<Map<int, bool>>();
  Stream<Map<int, bool>> get mapModelCheckbox => checkboxController.stream;
  Function(Map<int, bool>) get setCheckbox => checkboxController.sink.add;
  Item _item = Item();
  Map<int, bool> _mapCheckbox = HashMap<int, bool>();
  Map<int, String> _mapAmenities = HashMap<int, String>();

  AmenitiesBloc() {
    // Initial data for list and map
    List<Item> _theAmenities = _item.getItems();
    for (var i = 0; i < _theAmenities.length; i++) {
      _mapAmenities[i] = _theAmenities[i].title;
      _mapCheckbox[i] = false;
    }
    // Insert initial data in controller
    checkboxController.add(_mapCheckbox);
    checkboxController.stream.listen(setCheckboxHandler);
  }
  // Handler for checkbox state

  setCheckboxHandler(Map<int, bool> newMapCheckbox) {
    // New checkbox value for the itemModel id
    int id = newMapCheckbox.entries.elementAt(0).key;
    bool check = newMapCheckbox.entries.elementAt(0).value;
    if (_mapCheckbox.containsKey(id)) {
      _mapCheckbox[id] = check;
    }

    print('-----------');
    print('newMapCheckbox: $newMapCheckbox');
    print('_mapCheckbox: $_mapCheckbox');
    print('-----------');
    print(_mapCheckbox.length);
    List<String> a = _item.getAm(_mapCheckbox, _mapAmenities);

    print(a.toString());
    print(a.toString().runtimeType);
  }

  //dispose/close all the streams when we call dispose() method
  void dispose() {
    checkboxController.close();
  }
}