理论学习总是比较枯燥的,而且新接触一个东西的时候,如果都是理论学习很难让自己获得成就感和满足感,这样就很坚持下去了。
现在开始,来一个小小的实践练习,当将理论知识变成能看得到的画面的时候,成就感油然而生,给自己的理论学习增加动力。
准备工作
在终端执行命令,创建初始项目:
找到 main.dart 文件,将其中 _MyHomePageState 代码删减:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class _MyHomePageState extends State<MyHomePage> { void _incrementTodo() { setState(() { _counter++; }); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Text("Placeholder"), floatingActionButton: FloatingActionButton( onPressed: _incrementTodo, tooltip: 'Increment', child: const Icon(Icons.add), ), ); } }
|
数据准备
首先,我们需要每一行显示的数据,包含了:标题、描述和是否选中的状态三个数据。我们为此创建模型:
1 2 3 4 5 6 7 8 9 10 11
| class TodoModel { final String title; final String subTitle; bool isChecked;
TodoModel({ required this.title, required this.subTitle, this.isChecked = false }); }
|
然后,再来一个数组容器装着前面创建的模型数据,给列表提供数据就可以了。
变量以下划线 _ 开头,在 Dart 语言中使用下划线前缀标识符,会强制其变成私有的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class _MyHomePageState extends State<MyHomePage> {
final _todos = <TodoModel>[ TodoModel(title: "Todo_list Title", subTitle: "Todo_list Subtitle") ];
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Text("Placeholder") ); } }
|
创建列表
现在需要创建主体的列表了,这里新建一个方法,用来返回列表 ListView 的 Widget。这里使用了 ListView.separated 构造器,方便创建每个条目之间的分割线。
1 2 3 4 5 6 7 8 9 10 11 12 13
| Widget _buildList() { return ListView.separated( separatorBuilder: (context, index) => const Divider( thickness: 1, height: 1, color: Color.fromARGB(255, 232, 236, 236), ), itemCount: _todos.length, itemBuilder: (context, i) { return _buildItem(_todos[i]); } ); }
|
itemBuilder 会根据传入的数量,从 0 开始迭代并调用 itemBuilder 属性中传入的函数。这个函数返回每一行显示的 Item。
创建显示的 Item
同样的,新建一个方法 _buildItem 用来返回每一行 Item 显示的 Widget。这里 Todo 的显示样式,直接使用了系统提供的 CheckboxListTile 来显示。接下来开始编写这个函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| Widget _buildItem(TodoModel model) { return SizedBox( height: 60, child: CheckboxListTile( value: model.isChecked, title: Text( model.title, softWrap: false, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( color: Colors.black, fontSize: 18, fontWeight: FontWeight.w400 ), ), subtitle: Text( model.subTitle, softWrap: false, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( color: Colors.grey, fontSize: 14, fontWeight: FontWeight.normal ), ), // activeColor: Colors.red, dense: true, isThreeLine: false, controlAffinity: ListTileControlAffinity.leading, onChanged: (value) { setState(() { model.isChecked = value!; }); Future.delayed(const Duration(seconds: 1), (){ setState(() { _todos.remove(model); }); }); } ) ); }
|
在 CheckboxListTile 中,需要显示的数据都是来源于 _todos 的模型数据。在 CheckboxListTile 的 onChanged 的方法中,更改了当前 model 的数据,并刷新当前页面显示状态。并利用 Future 的 delayed 方法,延时 1s 将当前 勾选的 Todo 从列表中删除。
新增 Todo
这里直接使用项目初始化时,模板工程中的 FloatingActionButton 就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class _MyHomePageState extends State<MyHomePage> {
final _todos = <TodoModel>[ TodoModel(title: "Todo_list Title", subTitle: "Todo_list Subtitle") ];
int _count = 0;
void _incrementTodo() { setState(() { _counter++; // 将当前时间转化为字符串 var date = DateTime.now(); String createTime = "${date.year.toString()}-${date.month.toString()}-${date.day.toString()} ${date.hour.toString()}:${date.minute.toString()}"; _todos.add(TodoModel(title: "Todo_list Title - add $_count", subTitle: "create at $createTime")); }); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Text("Placeholder"), floatingActionButton: FloatingActionButton( onPressed: _incrementTodo, tooltip: 'Increment', child: const Icon(Icons.add), ), ); } }
|
组装完成
更新一下 _MyHomePageState 的 build 方法。将新建的列表创建方法传入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class _MyHomePageState extends State<MyHomePage> { ... @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: _buildList(), floatingActionButton: FloatingActionButton( onPressed: _incrementTodo, tooltip: 'Increment', child: const Icon(Icons.add), ), ); } ... }
|
好了,现在所有步骤都已经完成了,保存并重新运行程序,就可以得到一个和开篇时一样的项目了。