0.1:对我而言,一个产品有四层境界
代码语言:javascript复制1.造都造不出来
2.它又不是不能用 <----
3.用的时候大家都不说话
4.如丝般顺滑,易拓展,易修改,易复用
0.2:要说的话
注意:本篇是对状态最基本的使用。虽然比较糙,但是并不代表不重要 后面两篇是基于此篇的优化,所以这篇一定要看懂,才能跟上我的思维。 效果如下,单从界面上来看,我还是比较满意的。
0.3: 简介一下
代码语言:javascript复制本项目主要包括以下几点:
1. 输入一个待办事项,下面的ListView动态更新
2. 条目的复选框选中,条目的文字自动添加下划线
3. 条目的复选框非选中,条目的文字自动取消下划线
4. 三个按钮会根据是否完成而过滤数据,显示相应条目
1.静态界面的实现
代码语言:javascript复制万里长征第一步,当然是先把静态界面搞出了。
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.输入框的组件
代码语言:javascript复制通过一个TextField和RaisedButton进行拼合,样式什么的自己看,就不废话了。 我感觉这样挺好看的,不枉我精心调试一番。喜欢的话,可以自己抽个组件。
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.三个按钮
代码语言:javascript复制三个按钮,比较简单
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:根据数据形成列表
代码语言:javascript复制注意:如何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:拼组
代码语言:javascript复制这里要注意,用Expanded包一下,ListView才能自延展自己的尺寸 直接写的话啊,由于高度未知,会崩掉。
return Column(
children: <Widget>[inputBtn, op, Expanded(child: formList(todo))],
);
2.状态的更新
2.1:鸟瞰全局
代码语言:javascript复制这里状态有点乱,我画了幅图说明一下:
状态量有三个:text 输入框的文字,todo列表数据,showType展现类型
1.输入框通过监听,改变text的值
2.在添加按钮点击时,将加入到状态值todo中
3.todo用来渲染Todo列表,根据key和value展现数据和复选框状态
4.复选框通过点击,改变todo的状态,来显示对勾以及文字下划线
5.根据showType的不同,选择过滤的方式。
6.在适宜的状态值改变时,调用老夫的setState来更新
2.2:输入框监听
代码语言:javascript复制onChanged: (str) {
text = str;
},
2.3:点击按钮监听
代码语言:javascript复制注意收起键盘的操作
FocusScope.of(context).requestFocus(FocusNode());
onPressed: () {
FocusScope.of(context).requestFocus(FocusNode()); //收起键盘
if (text != null && text != "") {
todo[text] = false;//为Map添加数据
text = "";//输入框文字清空
setState(() {});
}
},
2.4:复选框点击
代码语言:javascript复制onChanged: (b) {
todo[key] = b;
setState(() {});
},
2.5:过滤操作
代码语言:javascript复制想了好一会,才想到该如何过滤出想要的元素
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:拼合
代码语言:javascript复制return Column(
children: <Widget>[inputBtn, op, Expanded(child: showList(showType))],
);
3. 代码全览
代码语言:javascript复制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
],
),
);
},
);
}
}
到这里效果就已经实现了,但是状态值四溢,看着感觉有些难看。 坏的代码就相当于你有个女友,又丑又乱,又凶又恶,有事没事给你找茬。 然而你还不得不一直面对她,问了你一句为什么这么傻,你含着泪说:"又不是不..."