Flutter學習(8)——CheckBox多選框使用及動態更改多選框數據


原文地址:Flutter學習(8)——CheckBox多選框使用及動態更改多選框數據 | Stars-One的雜貨小窩

最近項目需求需要調整頁面,記錄一下實現過程

這次主要是要實現個評價頁面,選擇不同的星級顯示不同的多選框數據,加上之前也沒有使用過CheckBox,今天便是一起講吧

本篇代碼github

效果預覽

效果看似有點復雜,我們一步步來實現吧 😄

1.星級組件使用

首先,我們有使用到星級評分組件pubspec.yaml文件中添加下面依賴

flutter_simple_rating_bar: ^0.0.3

使用的話頁面也是有個例子介紹,我們直接拿來即可使用

RatingBar(
		//默認選擇5星
		rating: 5,
        //總星星數目
        starCount: 5,
        //星星圖標
        icon: Icon(
            Icons.star,
            size: 40,
            color: Colors.grey,
        ),
        spacing: 5.0,
        size: 40,
        isIndicator: false,
        //是否可選半星
        allowHalfRating: true,
        onRatingCallback:(double value, ValueNotifier<bool> isIndicator) {
	        //value是點擊后選中的星星數(即評分),范圍為1-rating(我們上面rating為5)
            
        },
        color: Colors.amber,
)

現在我們要根據選擇⭐的數目不同,從而顯示不同的文字,這過程是動態的,所以我們選擇使用StatefulWidget作為頁面繼承的基類

我們先在State類中加上相應的數據,如下所示

//顯示的文字信息
List typeList = ["非常不滿意", "不滿意", "基本滿意", "滿意", "非常滿意"];

//當前選擇type的下標
int selectType = 4;

我們文字顯示內容是typeList[selectType],我們在星級評分選擇的回調函數,更改selecType即可實現更改UI的功能

Column(
    children: [
        RatingBar(
            rating: 5,
            //默認選擇5星
            starCount: 5,
            //總星星數目
            //星星圖標
            icon: Icon(
                Icons.star,
                size: 40,
                color: Colors.grey,
            ),
            spacing: 5.0,
            size: 40,
            isIndicator: false,
            //是否可選半星
            allowHalfRating: true,
            onRatingCallback:
            (double value, ValueNotifier<bool> isIndicator) {
                //更改數據同時也要更改UI,所以使用setState方法
                setState(() {
                    //注意 星級從1開始,selectType是下標,從0開始,需要減1
                    selectType = value.toInt() - 1;
                });
            },
            color: Colors.amber,
        ),
        //取指定下標的文字內容展示
        Text(typeList[selectType])
    ],
)
    

2.多選框使用及數據更改

CheckBox多選框的使用需要定義一個bool類型的數據,每次點擊需要更改此數據來改變CheckBox的選擇狀態

由於我們是使用的列表數據,所以每個數據寫個變量不太現實,而且繁瑣,所以可以考慮在實體類中加個bool類型的字段,用來存儲CheckBox選擇的狀態

這里,數據我就暫且寫死,實際上是要通過調用接口獲取的

void initTagData() {
    var data = """{
    "code":200,
    "error":"",
    "ReturnValue":[{"generalstars":"1","tagid":"109759610348409856","tagname":"無理由超過法定辦理時間","updatetime":"2020-06-12 17:38:00"},{"generalstars":"1","tagid":"6176177900787350","tagname":"在辦事指南之外增加新的審批條件","updatetime":"2020-08-27 00:00:00"},{"generalstars":"1","tagid":"6176177900787351","tagname":"需提供辦事指南之外的申報材料","updatetime":"2020-08-27 00:00:00"},{"generalstars":"1","tagid":"7176177890787535","tagname":"無理由超過法定辦理時間","updatetime":"2020-08-27 00:00:00"},{"generalstars":"2","tagid":"6176177900787349","tagname":"未在承諾時間內辦結","updatetime":"2020-08-27 00:00:00"},{"generalstars":"2","tagid":"6176177900787347","tagname":"沒有提供材料樣本","updatetime":"2020-08-27 00:00:00"},{"generalstars":"2","tagid":"6176177900787348","tagname":"沒有提供材料清單","updatetime":"2020-08-27 00:00:00"},{"generalstars":"3","tagid":"119596473292723200","tagname":"22222","updatetime":"2020-06-12 17:38:00"},{"generalstars":"3","tagid":"6176177900787346","tagname":"在承諾的時間內辦結","updatetime":"2020-08-27 00:00:00"},{"generalstars":"3","tagid":"6176177900787345","tagname":"提供申報材料樣本","updatetime":"2020-08-27 00:00:00"},{"generalstars":"3","tagid":"6176177900787344","tagname":"一次性告知需要補正的材料","updatetime":"2020-08-27 00:00:00"},{"generalstars":"4","tagid":"6176177900787340","tagname":"填寫一張表單就可以完成申報","updatetime":"2020-08-27 00:00:00"},{"generalstars":"4","tagid":"6176177900787341","tagname":"在線提交材料窗口核驗","updatetime":"2020-08-27 00:00:00"},{"generalstars":"4","tagid":"6176177900787342","tagname":"一張清單告知全部申報材料","updatetime":"2020-08-27 00:00:00"},{"generalstars":"5","tagid":"7176177890787335","tagname":"一窗受理一次辦結","updatetime":"2020-08-27 00:00:00"},{"generalstars":"5","tagid":"7176177890787235","tagname":"可以先受理后補材料","updatetime":"2020-08-27 00:00:00"},{"generalstars":"5","tagid":"7176177890787435","tagname":"不用提交證明","updatetime":"2020-08-27 00:00:00"}]
    }""";
    Map<String, dynamic> responseData = jsonDecode(data);
    var tagListModel = TagListModel.fromJson(responseData);
    if (tagListModel.code == 200) {
      //注意要使用setState,才會使UI發生變化(因為網絡請求是耗時任務,可能界面渲染完畢后才能請求到數據)
      setState(() {
        tagList.addAll(tagListModel.tagItems);
      });
    }
  }

TagListModel是生成的實體類,生成的步驟已經在上篇文章講解到,這里就不在贅述了

按照上面說的思路,我們在TagListModel的實體類中(其實是在TagItem中),添加一個bool類型的字段,用來作為存儲CheckBox選擇的狀態,

這里使用插件生成的實體類(TagListModel里面還包含有個實體類),原本應該是ReturnValue,但為了方便,我將其改了個名字TagItem

Flutter中的CheckBox是只有一個框,並不包含文字,所以我們得組合一個文本,拼成一個Widget,_tagView()這個方法就是每個選項

Widget _tagView(item) {
    var str = item.tagname;
    return InkWell(
        child: Row(
            children: <Widget>[
                Checkbox(
                    value: item.flag,
                    activeColor: Colors.blue,
                    onChanged: (bool val) {
                        // val 是布爾值
                        this.setState(() {
                            item.flag = val;
                        });
                    },
                ),
                Text(str),
            ],
        ),
        onTap: () {
            setState(() {
                item.flag = !item.flag;
            });
        },
   );
          

這里最外層使用了InkWell,是因為其有onTag的點擊事件方法 點擊整行都可以去改變CheckBox的狀態,用戶體驗比較友好,如果沒有的話,只能點擊CheckBox的框來改變狀態

有了上面的一個子項,現在我們需要構建一個多選選項列表(列表包含N個_tagView組件)

先聲明兩個數組,用來存放數據

//標簽數據(存放所有數據)
List<TagItem> tagList = [];

//臨時存放的數據,后面評價提交需要
List<TagItem> tempTagList = [];

這里為什么需要兩個數組呢?

主要是考慮到后面需要獲取勾選的數據,所以才考慮再多加一個臨時的列表

每次改變星級的時候,列表選項的數據就會改變,之后我們只需要去這個臨時列表中篩選狀態為true的數據即可

List<Widget> _tagList() {
    List<Widget> widgetList = [];
    var list = this.tagList;
    tempTagList.clear();

    var star = selectType.toInt() + 1;
    //匹配相同星級數據
    for (var i = 0; i < list.length; i++) {
      var item = list[i];
      if (item.generalstars == star.toString()) {
        //存在臨時表中,之后可以快速查找用戶的選擇
        tempTagList.add(item);
        var row = _tagView(item);
        widgetList.add(row);
      }
    }
    return widgetList;
}

由於數據較少,可以使用Column用來包裹上面的組件_tagList

//標簽選項
Container(
    decoration: BoxDecoration(color: Colors.white),
    padding: EdgeInsets.fromLTRB(10, 0, 15, 5),
    child: Column(
    	children: _tagList(),
    )
)

由於提交標簽需要傳標簽的id,而且需要逗號隔開,所以需要遍歷臨時選項列表,處理一下即可

//處理標簽
var tagId = "";
for (var i = 0; i < tempTagList.length; i++) {
    var item = tempTagList[i];
    //查找選擇的標簽數據
    if (item.flag) {
        tagId += item.tagid + ",";
    }
}
if (tagId.length>0) {
	tagId = tagId.substring(0, tagId.length - 1);
}
print(tagId);

源碼

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_demo/model/tag_list_model.dart';
import 'package:flutter_simple_rating_bar/flutter_simple_rating_bar.dart';

class CheckBoxPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new CheckBoxState();
  }
}

class CheckBoxState extends State<CheckBoxPage> {
  //標簽數據
  List<TagItem> tagList = [];

  //臨時標簽,后面評價提交需要
  List<TagItem> tempTagList = [];

  List typeList = ["非常不滿意", "不滿意", "基本滿意", "滿意", "非常滿意"];

  //當前選擇type的下標
  int selectType = 4;

  @override
  void initState() {
    //初始化數據(這里是暫時寫死,實際中這里是調用接口)
    initTagData();
  }

  void initTagData() {
    var data = """{
    "code":200,
    "error":"",
    "ReturnValue":[{"generalstars":"1","tagid":"109759610348409856","tagname":"無理由超過法定辦理時間","updatetime":"2020-06-12 17:38:00"},{"generalstars":"1","tagid":"6176177900787350","tagname":"在辦事指南之外增加新的審批條件","updatetime":"2020-08-27 00:00:00"},{"generalstars":"1","tagid":"6176177900787351","tagname":"需提供辦事指南之外的申報材料","updatetime":"2020-08-27 00:00:00"},{"generalstars":"1","tagid":"7176177890787535","tagname":"無理由超過法定辦理時間","updatetime":"2020-08-27 00:00:00"},{"generalstars":"2","tagid":"6176177900787349","tagname":"未在承諾時間內辦結","updatetime":"2020-08-27 00:00:00"},{"generalstars":"2","tagid":"6176177900787347","tagname":"沒有提供材料樣本","updatetime":"2020-08-27 00:00:00"},{"generalstars":"2","tagid":"6176177900787348","tagname":"沒有提供材料清單","updatetime":"2020-08-27 00:00:00"},{"generalstars":"3","tagid":"119596473292723200","tagname":"22222","updatetime":"2020-06-12 17:38:00"},{"generalstars":"3","tagid":"6176177900787346","tagname":"在承諾的時間內辦結","updatetime":"2020-08-27 00:00:00"},{"generalstars":"3","tagid":"6176177900787345","tagname":"提供申報材料樣本","updatetime":"2020-08-27 00:00:00"},{"generalstars":"3","tagid":"6176177900787344","tagname":"一次性告知需要補正的材料","updatetime":"2020-08-27 00:00:00"},{"generalstars":"4","tagid":"6176177900787340","tagname":"填寫一張表單就可以完成申報","updatetime":"2020-08-27 00:00:00"},{"generalstars":"4","tagid":"6176177900787341","tagname":"在線提交材料窗口核驗","updatetime":"2020-08-27 00:00:00"},{"generalstars":"4","tagid":"6176177900787342","tagname":"一張清單告知全部申報材料","updatetime":"2020-08-27 00:00:00"},{"generalstars":"5","tagid":"7176177890787335","tagname":"一窗受理一次辦結","updatetime":"2020-08-27 00:00:00"},{"generalstars":"5","tagid":"7176177890787235","tagname":"可以先受理后補材料","updatetime":"2020-08-27 00:00:00"},{"generalstars":"5","tagid":"7176177890787435","tagname":"不用提交證明","updatetime":"2020-08-27 00:00:00"}]
    }""";
    Map<String, dynamic> responseData = jsonDecode(data);
    var tagListModel = TagListModel.fromJson(responseData);
    if (tagListModel.code == 200) {
      //注意要使用setState,才會使UI發生變化(因為網絡請求是耗時任務,可能界面渲染完畢后才能請求到數據)
      setState(() {
        tagList.addAll(tagListModel.tagItems);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("評價"),
      ),
      body: Column(
        children: [
          Container(
            decoration: BoxDecoration(color: Colors.white),
            padding: EdgeInsets.fromLTRB(15, 0, 15, 10),
            child: Wrap(
              spacing: 10,
              children: [
                Center(
                  child: Column(
                    children: [
                      RatingBar(
                        rating: 5,
                        //默認選擇5星
                        starCount: 5,
                        //總星星數目
                        //星星圖標
                        icon: Icon(
                          Icons.star,
                          size: 40,
                          color: Colors.grey,
                        ),
                        spacing: 5.0,
                        size: 40,
                        isIndicator: false,
                        //是否可選半星
                        allowHalfRating: true,
                        onRatingCallback:
                            (double value, ValueNotifier<bool> isIndicator) {
                          //更改數據同時也要更改UI,所以使用setState方法
                          setState(() {
                            //注意 星級從1開始,selectType是下標,從0開始,需要減1
                            selectType = value.toInt() - 1;
                          });
                        },
                        color: Colors.amber,
                      ),
                      _tipText()
                    ],
                  ),
                )
              ],
            ),
          ),
          //標簽選項
          Container(
              decoration: BoxDecoration(color: Colors.white),
              padding: EdgeInsets.fromLTRB(10, 0, 15, 5),
              child: Column(
                children: _tagList(),
              )),
          Container(
              decoration: BoxDecoration(color: Colors.white),
              padding: EdgeInsets.fromLTRB(10, 0, 15, 5),
              child: FlatButton(
                child: Text("提交"),
                onPressed: () {
                  //處理標簽
                  var tagId = "";
                  for (var i = 0; i < tempTagList.length; i++) {
                    var item = tempTagList[i];
                    //查找選擇的標簽數據
                    if (item.flag) {
                      tagId += item.tagid + ",";
                    }
                  }
                  if (tagId.length>0) {
                    tagId = tagId.substring(0, tagId.length - 1);
                  }
                  print(tagId);
                },
              )),
        ],
      ),
    );
  }

  Widget _tipText() {
    //根據selectType變更UI
    return Text(typeList[selectType]);
  }

  List<Widget> _tagList() {
    List<Widget> widgetList = [];
    var list = this.tagList;
    tempTagList.clear();

    var star = selectType.toInt() + 1;
    for (var i = 0; i < list.length; i++) {
      var item = list[i];
      if (item.generalstars == star.toString()) {
        //存在臨時表中,之后可以快速查找用戶的選擇
        tempTagList.add(item);
        var row = _tagView(item);
        widgetList.add(row);
      }
    }
    return widgetList;
  }

  Widget _tagView(item) {
    var str = item.tagname;
    return InkWell(
      child: Row(
        children: <Widget>[
          Checkbox(
            value: item.flag,
            activeColor: Colors.blue,
            onChanged: (bool val) {
              // val 是布爾值
              this.setState(() {
                item.flag = val;
              });
            },
          ),
          Text(str),
        ],
      ),
      onTap: () {
        setState(() {
          item.flag = !item.flag;
        });
      },
    );
  }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM