我报名参加金石方案1期应战——分割10万奖池,这是我的第3篇文章,点击查看活动详情
今天,咱们将运用 Flutter
构建一个动态的 todo list
的使用。
开发完结的效果如下:
咱们直接进入正题。
根底 Flutter 使用脚手架
# create new project
flutter create flutter_todo_app
# navigate to project
cd flutter_todo_app
# run flutter
flutter run
咱们铲除文件 lib/main.dart
,从头开始开发。
main.dart 这个文件是 Flutter 使用的入口文件。在这篇文章中,我将仅仅运用这个文件来开发。
首先,咱们先导入 material
包。
import 'package:flutter/material.dart';
下一步,咱们得有一个主要的办法。在这个比如中,它将回来 TodoApp
实例。
void main() => runApp(
new TodoApp(),
);
这个 TodoApp
应该是一个 statelessWidget
。这将会是咱们列表的骨架
class TodoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Todo list',
home: new TodoList(),
);
}
}
正如你所见,我回来了一个 MaterialApp
实例,它具有一个 title
特点和一个 home
功用。这个 home
函数回来一个 TodoList
实例。这个 TodoList
类才是咱们操控的列表项。
class TodoList extends StatefulWidget {
@override
_TodoListState createState() => new _TodoListState();
}
等等,这是什么?所有的挂件都会调用一个状况去知道即将产生什么和烘托什么。在这个比如中,咱们调用了 _TodoListState
。这将包含使用中的列表及其运行逻辑。
class _TodoListState extends State<TodoList> {
final TextEditingController _textFieldController = TextEditingController();
final List<Todo> _todos = <Todo>[];
@override
Widget build(BuildContext context) {
// Widget template comes here
}
// Other functions
}
接下来,创立列表变量。
final List<Todo> _todos = <Todo>[];
或许你现已注意到了,咱们界说了这个列表的类型是 Todo
,但 Flutter
怎样知道 Todo
长是什么样呢?
Flutter
并不会知道,所以咱们得创立一个类来界说。如下:
class Todo {
Todo({required this.name, required this.checked});
final String name;
bool checked;
}
这跟 typescript
中的类型界说很像。咱们告诉 flutter
一个 todo 项应该包含什么,什么字段是有必要的。在咱们的案例中,咱们有名字和 checked
两个状况特点。
回到 _TodoListState
中,咱们开始让咱们的挂件展现点东西。
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Todo list'),
),
body: ListView(
padding: EdgeInsets.symmetric(vertical: 8.0),
children: _todos.map((Todo todo) {
return TodoItem(
todo: todo,
onTodoChanged: _handleTodoChange,
);
}).toList(),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _displayDialog(),
tooltip: 'Add Item',
child: Icon(Icons.add)),
);
}
让咱们看看上面产生了什么。咱们回来了使用的一个脚手架,在脚手架上,咱们增加了一个包含标题的 appBar
的特点。咱们界说了 body
特点,这将存放 ListView
组件。
在上面代码片段中,经过 map
办法回来每个元素的 TodoItem
。
然后,在使用的底部,咱们界说了一个按钮。当按钮被点击时分,将调用 _displayDialog
办法。
到目前为止,咱们还需要完结下面的代码片段:
- 创立
TodoItem
- 界说一个
_displayDialog
函数 - 界说一个
_handleTodoChange
函数
让咱们一个一个来解决。
创立 TodoItem
TodoItem
是咱们列表项的单独表现。
class TodoItem extends StatelessWidget {
TodoItem({
required this.todo,
required this.onTodoChanged,
}) : super(key: ObjectKey(todo));
final Todo todo;
final onTodoChanged;
TextStyle? _getTextStyle(bool checked) {
if (!checked) return null;
return TextStyle(
color: Colors.black54,
decoration: TextDecoration.lineThrough,
);
}
@override
Widget build(BuildContext context) {
return ListTile(
onTap: () {
onTodoChanged(todo);
},
leading: CircleAvatar(
child: Text(todo.name[0]),
),
title: Text(todo.name, style: _getTextStyle(todo.checked)),
);
}
}
正如你所见,咱们传递一个 todo
和 onTodoChanged
进来。
然后咱们界说了一个 TextStyle
去处理列表项是否被勾选。
然后咱们运用 ListTile
挂件来展现内容和增加点击事情。
展现 Dialog 去增加列表项
点击使用的右下角的按钮,将会调起 _displayDialog
办法。
这将调起一个带有文本框的对话框。当点击承认的时分,将以文本框的内容根底增加一个新的列表项。
在 _TodoListState
中创立 _displayDialog
。
Future<void> _displayDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Add a new todo item'),
content: TextField(
controller: _textFieldController,
decoration: const InputDecoration(hintText: 'Type your new todo'),
),
actions: <Widget>[
TextButton(
child: const Text('Add'),
onPressed: () {
Navigator.of(context).pop();
_addTodoItem(_textFieldController.text);
},
),
],
);
},
);
}
Flutter
中的 Future
表明在将来的某个时分将回来潜在的值或许错误信息。在咱们的案例中,将会回来用户输入的值。
对话框中有一个动作,便是当咱们点击按钮的时分,将会关闭对话框并且调用 _addTodoItem
函数。
咱们看看 _addTodoItem
函数长什么样:
void _addTodoItem(String name) {
setState(() {
_todos.add(Todo(name: name, checked: false));
});
_textFieldController.clear();
}
这函数比你想象中的简单,是吧。
列表项增加状况
最终一部分是,咱们应该为列表项进行标记。咱们需要一个处理函数 _handleTodoChange
:
void _handleTodoChange(Todo todo) {
setState(() {
todo.checked = !todo.checked;
});
}
这儿咱们仅仅改变了其列表项的状况。
完好的代码如下:
// lib/main.dart
import 'package:flutter/material.dart';
class Todo {
Todo({required this.name, required this.checked});
final String name;
bool checked;
}
class TodoItem extends StatelessWidget {
TodoItem({
required this.todo,
required this.onTodoChanged,
}) : super(key: ObjectKey(todo));
final Todo todo;
final onTodoChanged;
TextStyle? _getTextStyle(bool checked) {
if (!checked) return null;
return TextStyle(
color: Colors.black54,
decoration: TextDecoration.lineThrough,
);
}
@override
Widget build(BuildContext context) {
return ListTile(
onTap: () {
onTodoChanged(todo);
},
leading: CircleAvatar(
child: Text(todo.name[0]),
),
title: Text(todo.name, style: _getTextStyle(todo.checked)),
);
}
}
class TodoList extends StatefulWidget {
@override
_TodoListState createState() => new _TodoListState();
}
class _TodoListState extends State<TodoList> {
final TextEditingController _textFieldController = TextEditingController();
final List<Todo> _todos = <Todo>[];
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Todo list'),
),
body: ListView(
padding: EdgeInsets.symmetric(vertical: 8.0),
children: _todos.map((Todo todo) {
return TodoItem(
todo: todo,
onTodoChanged: _handleTodoChange,
);
}).toList(),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _displayDialog(),
tooltip: 'Add Item',
child: Icon(Icons.add)),
);
}
void _handleTodoChange(Todo todo) {
setState(() {
todo.checked = !todo.checked;
});
}
void _addTodoItem(String name) {
setState(() {
_todos.add(Todo(name: name, checked: false));
});
_textFieldController.clear();
}
Future<void> _displayDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Add a new todo item'),
content: TextField(
controller: _textFieldController,
decoration: const InputDecoration(hintText: 'Type your new todo'),
),
actions: <Widget>[
TextButton(
child: const Text('Add'),
onPressed: () {
Navigator.of(context).pop();
_addTodoItem(_textFieldController.text);
},
),
],
);
},
);
}
}
class TodoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Todo list',
home: new TodoList(),
);
}
}
void main() => runApp(new TodoApp());
本文选用的是意译的方法。原文链接 – Build a todo list app with Flutter
推荐阅览
- 求解波值的波峰和波谷「Javascript」
- 股票中 5 日均线(MA)你会画了?