1.造都造不出來
2.它又不是不能用 <----
3.用的時候你們都不說話
4.如絲般順滑,易拓展,易修改,易複用
複製代碼
注意:本篇是對狀態最基本的使用。雖然比較糙,可是並不表明不重要
後面兩篇是基於此篇的優化,因此這篇必定要看懂,才能跟上個人思惟。
效果以下,單從界面上來看,我仍是比較滿意的。git
本項目主要包括如下幾點:github
1. 輸入一個待辦事項,下面的ListView動態更新
2. 條目的複選框選中,條目的文字自動添加下劃線
3. 條目的複選框非選中,條目的文字自動取消下劃線
4. 三個按鈕會根據是否完成而過濾數據,顯示相應條目
複製代碼
萬里長征第一步,固然是先把靜態界面搞出了。bash
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();
}
}
複製代碼
經過一個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,
),
),
],
);
複製代碼
三個按鈕,比較簡單ide
var op = Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
RaisedButton(
color: Colors.blue,
onPressed: () {
},
child: Text("所有"),
),
RaisedButton(
onPressed: () {
},
child: Text("已完成"),
),
RaisedButton(
onPressed: () {
},
child: Text("未完成"),
),
],
);
複製代碼
用一個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;//顯示類型
}
複製代碼
注意:如何Map獲取對應索引處的鍵,值。根據值的true/fase來控制decoration的有無post
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
],
),
);
},
);
}
複製代碼
這裏要注意,用Expanded包一下,ListView才能自延展本身的尺寸
直接寫的話啊,因爲高度未知,會崩掉。優化
return Column(
children: <Widget>[inputBtn, op, Expanded(child: formList(todo))],
);
複製代碼
這裏狀態有點亂,我畫了幅圖說明一下:ui
狀態量有三個:text 輸入框的文字,todo列表數據,showType展示類型
1.輸入框經過監聽,改變text的值
2.在添加按鈕點擊時,將加入到狀態值todo中
3.todo用來渲染Todo列表,根據key和value展示數據和複選框狀態
4.複選框經過點擊,改變todo的狀態,來顯示對勾以及文字下劃線
5.根據showType的不一樣,選擇過濾的方式。
6.在適宜的狀態值改變時,調用老夫的setState來更新
複製代碼
onChanged: (str) {
text = str;
},
複製代碼
注意收起鍵盤的操做
FocusScope.of(context).requestFocus(FocusNode());
this
onPressed: () {
FocusScope.of(context).requestFocus(FocusNode()); //收起鍵盤
if (text != null && text != "") {
todo[text] = false;//爲Map添加數據
text = "";//輸入框文字清空
setState(() {});
}
},
複製代碼
onChanged: (b) {
todo[key] = b;
setState(() {});
},
複製代碼
想了好一會,纔想到該如何過濾出想要的元素spa
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;
}
}
複製代碼
return Column(
children: <Widget>[inputBtn, op, Expanded(child: showList(showType))],
);
複製代碼
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
],
),
);
},
);
}
}
複製代碼
到這裏效果就已經實現了,可是狀態值四溢,看着感受有些難看。
壞的代碼就至關於你有個女朋友,又醜又亂,又兇又惡,有事沒事給你找茬。
然而你還不得不一直面對她,問了你一句爲何這麼傻,你含着淚說:"又不是不..."
本文到此接近尾聲了,若是想快速嚐鮮Flutter,《Flutter七日》會是你的必備佳品;若是想細細探究它,那就跟隨個人腳步,完成一次Flutter之旅。
另外本人有一個Flutter微信交流羣,歡迎小夥伴加入,共同探討Flutter的問題,本人微信號:zdl1994328
,期待與你的交流與切磋。
下一篇,將爲你帶來如何對當前代碼進行優化,讓狀態量更容易管理,敬請期待。