34
loading...
This website collects cookies to deliver better user experience
# create new project
flutter create flutter_todo_app
# navigate to project
cd flutter_todo_app
# run flutter
flutter run
lib/main.dart
file.Note: this is the main entry point for our Flutter app. For this article, I'll only be using that file.
import 'package:flutter/material.dart';
TodoApp
, which we will create in a second.void main() => runApp(
new TodoApp(),
);
class TodoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Todo list',
home: new TodoList(),
);
}
}
MaterialApp
and pass a title and the home function.TodoList
, another function we'll be making ourselves.TodoList
will be our actual list and control the state of all the todo items in it.class TodoList extends StatefulWidget {
@override
_TodoListState createState() => new _TodoListState();
}
_TodoListState
. This will have all the list and logic for our app.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
, but how would Flutter know what a todo looks like?main.dart
file right below the import.class Todo {
Todo({required this.name, required this.checked});
final String name;
bool checked;
}
_TodoListState
, we can start working on our widget to display something.@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)),
);
}
ListView
widget with todo's as children.TodoItem
for each element. We pass the todo and a change handler to this widget._displayDialog
when pressed.TodoItem
_displayDialog
function_handleTodoChange
functionclass 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)),
);
}
}
TextStyle
. This takes a boolean to evaluate whether a todo is checked or not.ListTile
widget, and add a onTap to invoke the onTodoChanged
function._displayDialog
when we click it._displayDialog
inside the _TodoListState
.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);
},
),
],
);
},
);
}
TextField
widget._addTodoItem
function._addTodoItem
function will look.void _addTodoItem(String name) {
setState(() {
_todos.add(Todo(name: name, checked: false));
});
_textFieldController.clear();
}
add
functionality build in. We don't need to write that ourselves._handleTodoChange
function._TodoListState
.void _handleTodoChange(Todo todo) {
setState(() {
todo.checked = !todo.checked;
});
}