Learn how to build a user interface for a Todo app using the Provider package in Flutter. This guide covers designing the main screen, creating a Todo item widget, building add/edit screens, implementing navigation, and ensuring UI updates.
In this section, we will explore how to build a user interface for a Todo app using the Provider package in Flutter. This comprehensive guide will walk you through designing the main screen to display the list of todos, creating a Todo item widget, building add/edit screens, implementing navigation, and ensuring that the UI updates in response to changes in the provider. By the end of this section, you will have a functional Todo app UI that effectively utilizes the Provider for state management.
The Todo List Screen is the heart of our application, where users can view all their todos. We’ll use a ListView.builder
to create a scrollable list of todos. This approach is efficient for displaying large lists as it only builds the widgets that are visible on the screen.
To design the main screen, we will use the Consumer<TodoProvider>
widget to access the list of todos from the provider. This allows us to rebuild the UI whenever the list of todos changes.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'todo_provider.dart'; // Assume this is where your provider is defined
class TodoListScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Todo List'),
),
body: Consumer<TodoProvider>(
builder: (context, todoProvider, child) {
return ListView.builder(
itemCount: todoProvider.todos.length,
itemBuilder: (context, index) {
var todo = todoProvider.todos[index];
return TodoItemWidget(todo: todo);
},
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AddEditTodoScreen()),
);
},
child: Icon(Icons.add),
),
);
}
}
Key Points:
Consumer<TodoProvider>
to listen to changes in the TodoProvider
. This ensures that the ListView
updates whenever the list of todos changes.AddEditTodoScreen
for adding new todos.Each todo item in the list will be represented by a separate widget. This widget will display the title and completion status of the todo and provide interaction capabilities such as tapping or swiping to edit or delete the todo.
import 'package:flutter/material.dart';
import 'todo.dart'; // Assume this is your Todo model
class TodoItemWidget extends StatelessWidget {
final Todo todo;
TodoItemWidget({required this.todo});
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(todo.title),
trailing: Checkbox(
value: todo.isCompleted,
onChanged: (bool? value) {
// Update the completion status
},
),
onTap: () {
// Navigate to edit screen
},
onLongPress: () {
// Show options to delete
},
);
}
}
Key Points:
onTap
and onLongPress
to handle interactions like editing or deleting a todo.This screen will allow users to add a new todo or edit an existing one. We’ll use TextFormField
widgets for input and implement form validation to ensure that users provide valid data.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'todo_provider.dart';
import 'todo.dart';
class AddEditTodoScreen extends StatefulWidget {
final Todo? todo;
AddEditTodoScreen({this.todo});
@override
_AddEditTodoScreenState createState() => _AddEditTodoScreenState();
}
class _AddEditTodoScreenState extends State<AddEditTodoScreen> {
final _formKey = GlobalKey<FormState>();
late String _title;
@override
void initState() {
super.initState();
_title = widget.todo?.title ?? '';
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.todo == null ? 'Add Todo' : 'Edit Todo'),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
initialValue: _title,
decoration: InputDecoration(labelText: 'Title'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a title';
}
return null;
},
onSaved: (value) {
_title = value!;
},
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
if (widget.todo == null) {
Provider.of<TodoProvider>(context, listen: false)
.addTodo(Todo(title: _title));
} else {
Provider.of<TodoProvider>(context, listen: false)
.updateTodo(widget.todo!.copyWith(title: _title));
}
Navigator.pop(context);
}
},
child: Text(widget.todo == null ? 'Add' : 'Update'),
),
],
),
),
),
);
}
}
Key Points:
Form
widget with a GlobalKey
to validate and save form data.Navigation between screens is crucial for a seamless user experience. We’ll use Navigator.push
to transition between the Todo List Screen and the Add/Edit Todo Screen.
The navigation logic is already integrated into the FloatingActionButton
and onTap
methods in the previous examples. Here’s a quick recap:
FloatingActionButton
to navigate to the AddEditTodoScreen
.onTap
method in TodoItemWidget
to navigate to the AddEditTodoScreen
with the selected todo.Ensuring that the UI updates in response to changes in the provider is essential for a responsive app. The Consumer
widget handles this by listening to changes in the provider and rebuilding the UI accordingly.
To verify that the UI updates correctly, perform the following tests:
Building a user interface for a Todo app using the Provider package in Flutter involves designing a responsive main screen, creating interactive todo item widgets, building forms for adding and editing todos, and implementing seamless navigation. By following the steps outlined in this guide, you can create a functional and efficient UI that leverages the power of Provider for state management.