为了账号安全,请及时绑定邮箱和手机立即绑定

TodoList深入Flutter状态管理(上篇)

标签:
Android

上篇: 又不是不能用-篇  本文源码Github

0.1:对我而言,一个产品有四层境界
1.造都造不出来 2.它又不是不能用    <---- 3.用的时候大家都不说话 4.如丝般顺滑,易拓展,易修改,易复用 复制代码


1



0.2:要说的话

注意:本篇是对状态最基本的使用。虽然比较糙,但是并不代表不重要
后面两篇是基于此篇的优化,所以这篇一定要看懂,才能跟上我的思维。
效果如下,单从界面上来看,我还是比较满意的。


16c2c4195288537e?imageslim



0.3: 简介一下

本项目主要包括以下几点:

1. 输入一个待办事项,下面的ListView动态更新   2. 条目的复选框选中,条目的文字自动添加下划线 3. 条目的复选框非选中,条目的文字自动取消下划线 4. 三个按钮会根据是否完成而过滤数据,显示相应条目 复制代码

1.静态界面的实现

万里长征第一步,当然是先把静态界面搞出了。

import 'package:flutter/material.dart'; class TodoList extends StatefulWidget {   @override   _TodoListState createState() => _TodoListState(); } class _TodoListState extends State<TodoList> {   @override   Widget build(BuildContext context) {         return Container();   } } 复制代码

1.1.输入框的组件

通过一个TextField和RaisedButton进行拼合,样式什么的自己看,就不废话了。
我感觉这样挺好看的,不枉我精心调试一番。喜欢的话,可以自己抽个组件。


1


var textField = TextField(   controller: new TextEditingController(text: this.text),   keyboardType: TextInputType.text,   textAlign: TextAlign.start,   maxLines: 1,   cursorColor: Colors.black,   cursorWidth: 3,   style: TextStyle(       fontSize: 16, color: Colors.lightBlue, backgroundColor: Colors.white),   decoration: InputDecoration(     filled: true,     fillColor: Colors.white,     hintText: '添加一个待办项',     hintStyle: TextStyle(color: Colors.black26, fontSize: 14),     contentPadding: EdgeInsets.only(left: 14.0, bottom: 8.0, top: 8.0),     focusedBorder: OutlineInputBorder(       borderSide: BorderSide(color: Colors.white),       borderRadius: BorderRadius.only(           topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),     ),     enabledBorder: UnderlineInputBorder(       borderSide: BorderSide(color: Colors.white),       borderRadius: BorderRadius.only(           topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),     ),   ),   onChanged: (str) {     //输入时的回调   }, ); var btn = RaisedButton(   child: Icon(Icons.add),   padding: EdgeInsets.zero,   onPressed: () {     //按钮点击回调   }, ); var inputBtn = Row(   mainAxisAlignment: MainAxisAlignment.center,   children: <Widget>[     Container(       child: textField,       width: 200,     ),     ClipRRect(       borderRadius: BorderRadius.only(           topRight: Radius.circular(10), bottomRight: Radius.circular(10)),       child: Container(         child: btn,         width: 36,         height: 36,       ),     ),   ], ); 复制代码

1.2.三个按钮

三个按钮,比较简单


1


var op = Row(   mainAxisAlignment: MainAxisAlignment.spaceEvenly,   children: <Widget>[     RaisedButton(       color: Colors.blue,       onPressed: () {       },       child: Text("全部"),     ),     RaisedButton(       onPressed: () {       },       child: Text("已完成"),     ),     RaisedButton(       onPressed: () {       },       child: Text("未完成"),     ),   ], ); 复制代码

1.3.待准备的数据
  • 用一个Map盛放文字和是否选中的

var todo = <String, bool>{}; 复制代码
  • 定义一个状态枚举

enum ShowType {      all,      todo,      done  } 复制代码
  • 类中设置初始变量

class _TodoListState extends State<TodoList> {   var todo = <String, bool>{};//列表数据   var text;//当前输入文字   var showType = ShowType.all;//显示类型 } 复制代码

1.4:根据数据形成列表

注意:如何Map获取对应索引处的键,值。根据值的true/fase来控制decoration的有无

Widget formList(Map<String, bool> todo) {     return ListView.builder(       itemCount: todo.length,       padding: EdgeInsets.all(8.0),       itemExtent: 50.0,       itemBuilder: (BuildContext context, int index) {         var key = todo.keys.toList()[index];//键         var value = todo.values.toList()[index];//值         var text = Align(           child: Text(             todo.keys.toList()[index],             style: TextStyle(               decorationThickness: 3,                 decoration: value                     ? TextDecoration.lineThrough                     : TextDecoration.none,                 decorationColor: Colors.blue),           ),           alignment: Alignment.centerLeft,         );         return Card(           child: Row(             children: <Widget>[               Checkbox(                 onChanged: (b) {                  //Checkbox点击                 },                 value: todo.values.toList()[index],               ),               text             ],           ),         );       },     );   } 复制代码

1.5:拼组

这里要注意,用Expanded包一下,ListView才能自延展自己的尺寸
直接写的话啊,由于高度未知,会崩掉。

return Column(   children: <Widget>[inputBtn, op, Expanded(child: formList(todo))], ); 复制代码

2.状态的更新

2.1:鸟瞰全局

这里状态有点乱,我画了幅图说明一下:


1


状态量有三个:text 输入框的文字,todo列表数据,showType展现类型 1.输入框通过监听,改变text的值 2.在添加按钮点击时,将加入到状态值todo中  3.todo用来渲染Todo列表,根据key和value展现数据和复选框状态 4.复选框通过点击,改变todo的状态,来显示对勾以及文字下划线 5.根据showType的不同,选择过滤的方式。 6.在适宜的状态值改变时,调用老夫的setState来更新 复制代码

2.2:输入框监听
onChanged: (str) {   text = str; }, 复制代码

2.3:点击按钮监听

注意收起键盘的操作FocusScope.of(context).requestFocus(FocusNode());

onPressed: () {   FocusScope.of(context).requestFocus(FocusNode()); //收起键盘   if (text != null && text != "") {     todo[text] = false;//为Map添加数据     text = "";//输入框文字清空     setState(() {});   } }, 复制代码

2.4:复选框点击
onChanged: (b) {   todo[key] = b;   setState(() {}); }, 复制代码

2.5:过滤操作

想了好一会,才想到该如何过滤出想要的元素

showList(ShowType showType) {   switch (showType) {     case ShowType.all:       return formList(todo);       break;     case ShowType.todo:       return formList(Map.fromEntries(todo.entries.where((e) => !e.value)));       break;     case ShowType.done:       return formList(Map.fromEntries(todo.entries.where((e) => e.value)));       break;   } } 复制代码

2.6:拼合
return Column(   children: <Widget>[inputBtn, op, Expanded(child: showList(showType))], ); 复制代码

3. 代码全览

import 'package:flutter/material.dart'; class TodoList extends StatefulWidget {   @override   _TodoListState createState() => _TodoListState(); } enum ShowType { all, todo, done } class _TodoListState extends State<TodoList> {   var todo = <String, bool>{};//列表数据   var text;//当前输入文字   var showType = ShowType.all;//显示类型   @override   Widget build(BuildContext context) {     var textField = TextField(       controller: new TextEditingController(text: this.text),       keyboardType: TextInputType.text,       textAlign: TextAlign.start,       maxLines: 1,       cursorColor: Colors.black,       cursorWidth: 3,       style: TextStyle(           fontSize: 16, color: Colors.lightBlue, backgroundColor: Colors.white),       decoration: InputDecoration(         filled: true,         fillColor: Colors.white,         hintText: '添加一个待办项',         hintStyle: TextStyle(color: Colors.black26, fontSize: 14),         contentPadding: EdgeInsets.only(left: 14.0, bottom: 8.0, top: 8.0),         focusedBorder: OutlineInputBorder(           borderSide: BorderSide(color: Colors.white),           borderRadius: BorderRadius.only(               topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),         ),         enabledBorder: UnderlineInputBorder(           borderSide: BorderSide(color: Colors.white),           borderRadius: BorderRadius.only(               topLeft: Radius.circular(10), bottomLeft: Radius.circular(10)),         ),       ),       onChanged: (str) {         text = str;       },     );     var btn = RaisedButton(       child: Icon(Icons.add),       padding: EdgeInsets.zero,       onPressed: () {         FocusScope.of(context).requestFocus(FocusNode()); //收起键盘         if (text != null && text != "") {           todo[text] = false;           text = "";           setState(() {});         }       },     );     var inputBtn = Row(       mainAxisAlignment: MainAxisAlignment.center,       children: <Widget>[         Container(           child: textField,           width: 200,         ),         ClipRRect(           borderRadius: BorderRadius.only(               topRight: Radius.circular(10), bottomRight: Radius.circular(10)),           child: Container(             child: btn,             width: 36,             height: 36,           ),         ),       ],     );     var op = Row(       mainAxisAlignment: MainAxisAlignment.spaceEvenly,       children: <Widget>[         RaisedButton(           color: Colors.blue,           textTheme: ButtonTextTheme.primary,           onPressed: () {             showType = ShowType.all;             setState(() {});           },           child: Text("全部"),         ),         RaisedButton(           onPressed: () {             showType = ShowType.done;             setState(() {});           },           child: Text("已完成"),         ),         RaisedButton(           onPressed: () {             showType = ShowType.todo;             setState(() {});           },           child: Text("未完成"),         ),       ],     );     return Column(       children: <Widget>[inputBtn, op, Expanded(child: showList(showType))],     );   }   showList(ShowType showType) {     switch (showType) {       case ShowType.all:         return formList(todo);         break;       case ShowType.todo:         return formList(Map.fromEntries(todo.entries.where((e) => !e.value)));         break;       case ShowType.done:         return formList(Map.fromEntries(todo.entries.where((e) => e.value)));         break;     }   }   Widget formList(Map<String, bool> todo) {     return ListView.builder(       itemCount: todo.length,       padding: EdgeInsets.all(8.0),       itemExtent: 50.0,       itemBuilder: (BuildContext context, int index) {         var key = todo.keys.toList()[index];         var value = todo.values.toList()[index];         var text = Align(           child: Text(             todo.keys.toList()[index],             style: TextStyle(               decorationThickness: 3,                 decoration: value                     ? TextDecoration.lineThrough                     : TextDecoration.none,                 decorationColor: Colors.blue),           ),           alignment: Alignment.centerLeft,         );         return Card(           child: Row(             children: <Widget>[               Checkbox(                 onChanged: (b) {                   todo[key] = b;                   setState(() {});                 },                 value: todo.values.toList()[index],               ),               text             ],           ),         );       },     );   } } 复制代码

到这里效果就已经实现了,但是状态值四溢,看着感觉有些难看。
坏的代码就相当于你有个女友,又丑又乱,又凶又恶,有事没事给你找茬。
然而你还不得不一直面对她,问了你一句为什么这么傻,你含着泪说:"又不是不..."



点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消