In our previous post, we implemented a simple UI for a To-Do list app. This time, we’ll add state management to implement functionality for adding new todos and changing their completion status.
1. Converting to StatefulWidget
First, we need to change TodoListScreen
and TodoList
to StatefulWidget
s. This allows us to change the state of the widgets.
Modify the lib/main.dart
file as follows:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'To-Do List',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: TodoListScreen(),
);
}
}
class TodoListScreen extends StatefulWidget {
@override
_TodoListScreenState createState() => _TodoListScreenState();
}
class _TodoListScreenState extends State<TodoListScreen> {
List<Todo> todos = [];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My To-Do List'),
),
body: TodoList(todos: todos, onTodoToggle: _toggleTodo),
floatingActionButton: FloatingActionButton(
onPressed: _addTodo,
child: Icon(Icons.add),
),
);
}
void _addTodo() {
showDialog(
context: context,
builder: (BuildContext context) {
String newTodo = "";
return AlertDialog(
title: Text('Add a new todo'),
content: TextField(
onChanged: (value) {
newTodo = value;
},
),
actions: <Widget>[
TextButton(
child: Text('Add'),
onPressed: () {
setState(() {
todos.add(Todo(title: newTodo));
});
Navigator.of(context).pop();
},
),
],
);
},
);
}
void _toggleTodo(Todo todo) {
setState(() {
todo.isCompleted = !todo.isCompleted;
});
}
}
class TodoList extends StatelessWidget {
final List<Todo> todos;
final Function(Todo) onTodoToggle;
TodoList({required this.todos, required this.onTodoToggle});
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(
todos[index].title,
style: TextStyle(
decoration: todos[index].isCompleted ? TextDecoration.lineThrough : null,
),
),
trailing: Checkbox(
value: todos[index].isCompleted,
onChanged: (_) => onTodoToggle(todos[index]),
),
);
},
);
}
}
class Todo {
String title;
bool isCompleted;
Todo({required this.title, this.isCompleted = false});
}
2. Code Explanation
Todo
class: A model class representing each todo item._TodoListScreenState
class:_addTodo()
method: Displays a dialog to add a new todo._toggleTodo()
method: Toggles the completion status of a todo.TodoList
class: Displays the list of todos and changes the style based on each item’s completion status.
3. Key Concepts Explained
StatefulWidget
: A widget that can have mutable state.setState()
: Notifies Flutter that the widget’s state has changed and the UI should be redrawn.showDialog()
: Displays a popup dialog.AlertDialog
: A dialog for user input.
4. Running the App
In your terminal, run the following command to start the app:
flutter run
Now when you run the app, you can add new todos and change their completion status.
Wrap-up
In this post, we added state management to our To-Do list app, turning it into a functional application. Through this, we learned about basic state management concepts in Flutter and how to handle user interactions.
In our next post, we’ll explore how to save the app’s data to local storage so that the data persists even when the app is closed and reopened.
If you have any questions about Flutter development, feel free to leave a comment below!
Related Resources
- Flutter State Management Documentation: https://flutter.dev/docs/development/data-and-backend/state-mgmt
- Flutter Dialog Widget: https://api.flutter.dev/flutter/material/AlertDialog-class.html