Simple Flutter App: Todo List app


Features

  • Add and remove tasks.
  • Use List to manage tasks.

Concepts Used

  • Collections (Lists)
  • Functions

Implementation

  • UI: TextField to add tasks, and a list to display tasks with delete buttons.

Final Result

How the App Works

  1. Add a Task:
    • The user types a task into the input field and presses the “+” button.
    • The addTask() function adds the task to the _tasks list and updates the UI.
  2. Display Tasks:
    • All tasks in the _tasks list are displayed in a scrollable ListView.
  3. Remove a Task:
    • The user presses the trash icon next to a task.
    • The removeTask() function removes the task from _tasks and updates the UI.

Code

lib/todo_list_app.dart

import 'package:flutter/material.dart';

class TodoListApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: TodoListScreen(),
    );
  }
}

class TodoListScreen extends StatefulWidget {
  @override
  _TodoListScreenState createState() => _TodoListScreenState();
}

class _TodoListScreenState extends State<TodoListScreen> {
  final List<String> _tasks = []; // List to store tasks
  final TextEditingController _controller = TextEditingController(); // Controller for the input field

  void addTask() {
    final task = _controller.text.trim(); // Get and clean input text
    if (task.isNotEmpty) {
      setState(() {
        _tasks.add(task); // Add task to the list
      });
      _controller.clear(); // Clear input field after adding
    }
  }

  void removeTask(int index) {
    setState(() {
      _tasks.removeAt(index); // Remove task by index
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('To-Do List')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _controller,
                    decoration: InputDecoration(labelText: 'Enter a task'),
                  ),
                ),
                IconButton(
                  icon: Icon(Icons.add),
                  onPressed: addTask,
                ),
              ],
            ),
            SizedBox(height: 20),
            Expanded(
              child: ListView.builder(
                itemCount: _tasks.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    title: Text(_tasks[index]),
                    trailing: IconButton(
                      icon: Icon(Icons.delete),
                      onPressed: () => removeTask(index), // Delete task
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Code Explanation

The To-Do List App allows users to add and remove tasks dynamically. Tasks are stored in a list and displayed on the screen. The app uses Flutter widgets and Dart collections to manage and display the tasks.

Entry Point (main.dart)

import 'package:flutter/material.dart';
import 'package:todo_list_app/todo_list_app.dart';
void main() {
  runApp(TodoListApp());
}
  • Purpose: The main() function launches the app.
  • runApp(TodoListApp()): Specifies TodoListApp as the root widget.

TodoListApp Class

class TodoListApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: TodoListScreen(),
    );
  }
}
  • MaterialApp:
    • Sets up the app with Material Design.
    • Disables the debug banner using debugShowCheckedModeBanner: false.
    • Specifies the TodoListScreen as the home screen.

TodoListScreen Class

class TodoListScreen extends StatefulWidget {
  @override
  _TodoListScreenState createState() => _TodoListScreenState();
}
  • Purpose: Represents the main screen where users can manage their tasks.
  • StatefulWidget: Used because the list of tasks changes dynamically.

Task Management

Task Storage
final List<String> _tasks = [];
  • Purpose: Stores all the tasks as a list of strings.
  • Dynamic Updates: Tasks are added or removed using setState().

Adding a Task

void addTask() {
  final task = _controller.text.trim(); // Get and clean input text
  if (task.isNotEmpty) {
    setState(() {
      _tasks.add(task); // Add task to the list
    });
    _controller.clear(); // Clear input field after adding
  }
}
  • Input Handling: Retrieves the text from _controller, trims it, and ensures it’s not empty.
  • Updating State:
    • Calls setState() to add the new task to _tasks.
    • Updates the UI to show the new task immediately.
  • Clear Input: Clears the TextField after the task is added.

Removing a Task

void removeTask(int index) {
  setState(() {
    _tasks.removeAt(index); // Remove task by index
  });
}
  • Task Removal:
    • Removes the task at the specified index.
    • Updates the UI dynamically using setState().

Building the UI

Input Field and Add Button
Row(
  children: [
    Expanded(
      child: TextField(
        controller: _controller,
        decoration: InputDecoration(labelText: 'Enter a task'),
      ),
    ),
    IconButton(
      icon: Icon(Icons.add),
      onPressed: addTask,
    ),
  ],
)
  • Row Layout:
    • Contains the TextField and an Add Button (IconButton).
  • TextField:
    • Uses _controller to capture user input.
    • Includes a placeholder label ('Enter a task').
  • IconButton:
    • Displays a “+” icon (Icons.add).
    • Calls addTask() when pressed.

Task List Display

Expanded(
  child: ListView.builder(
    itemCount: _tasks.length,
    itemBuilder: (context, index) {
      return ListTile(
        title: Text(_tasks[index]), // Task name
        trailing: IconButton(
          icon: Icon(Icons.delete),
          onPressed: () => removeTask(index), // Delete task
        ),
      );
    },
  ),
),

ListView.builder:

  • Dynamically builds a scrollable list of tasks.
  • itemCount: The number of tasks (_tasks.length).
  • itemBuilder: A function to generate each ListTile.

ListTile:

  • title: Displays the task text.
  • trailing: Adds a delete button (trash icon).

IconButton:

  • Displays a delete icon (Icons.delete).
  • Calls removeTask() with the task index when pressed.

Complete Widget Tree

return Scaffold(
  appBar: AppBar(title: Text('To-Do List')),
  body: Padding(
    padding: const EdgeInsets.all(16.0),
    child: Column(
      children: [
        Row(...), // Input field and add button
        SizedBox(height: 20),
        Expanded(...), // Task list
      ],
    ),
  ),
);
  • Scaffold:
    • Provides a layout with an app bar and body.
  • Padding:
    • Adds padding around the body.
  • Column:
    • Stacks the input field, add button, and task list vertically.
  • Row:
    • Horizontally arranges the TextField and Add Button.

Key Flutter Concepts Used

  1. State Management:
    • setState() dynamically updates the UI whenever tasks are added or removed.
  2. Lists in Dart:
    • List<String> stores the tasks.
  3. Text Input:
    • TextField captures user input with a TextEditingController.
  4. Dynamic Widgets:
    • ListView.builder creates widgets dynamically based on the number of tasks.
  5. Icons and Buttons:
    • IconButton is used for the Add Task and Delete Task actions.