Menu
CoddyTech

Lista delle cose da fare: scorri per eliminare

Fa parte della sezione Progetti del percorso Flutter di Coddy. Lezione 6 di 36.

Su un telefono, elimini un'attività completata facendola scorrere via con un gesto. Avvolgi ogni riga in un Dismissible e Flutter farà scorrere la riga per te:

Dismissible(
  key: ObjectKey(task),
  direction: DismissDirection.endToStart,
  background: Container(color: Colors.red, ...),
  onDismissed: (direction) => _deleteTask(task),
  child: ListTile(...),
)

La key indica a Flutter quale sia ciascuna riga, così fa scorrere via quella giusta. ObjectKey(task) la associa all'attività stessa. endToStart indica uno scorrimento verso sinistra, mentre background è ciò che appare dietro la riga mentre scorre: rosso, con un'icona di eliminazione a destra.

onDismissed viene eseguito quando la riga scompare dallo schermo. Il tuo compito è rimuovere l'attività dall'elenco, all'interno di setState. Rimuovi l'attività stessa, non una posizione, così verrà rimossa quella giusta anche se l'elenco cambia in seguito.

challenge icon

Sfida

Medio

Elimina le attività con uno scorrimento:

  • aggiungi un metodo _deleteTask(Task task) che rimuove l'attività all'interno di setState
  • racchiudi ogni ListTile in un Dismissible con key: ObjectKey(task) che viene fatto scorrere verso sinistra
  • il suo background è un Container rosso con un Icons.delete bianco sulla destra, a 24 pixel dal bordo

Provalo tu

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
      ),
      home: const TodoScreen(),
    );
  }
}

class Task {
  Task(this.title);

  final String title;
  bool done = false;
}

class TodoScreen extends StatefulWidget {
  const TodoScreen({super.key});

  @override
  State<TodoScreen> createState() => _TodoScreenState();
}

class _TodoScreenState extends State<TodoScreen> {
  final List<Task> _tasks = [Task('Buy milk'), Task('Walk the dog'), Task('Read a book')];
  final _controller = TextEditingController();

  int get _left => _tasks.where((task) => !task.done).length;

  void _addTask() {
    final title = _controller.text.trim();
    if (title.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Type a task first')),
      );
      return;
    }
    setState(() {
      _tasks.add(Task(title));
    });
    _controller.clear();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('My Tasks')),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _controller,
                    decoration: const InputDecoration(
                      labelText: 'New task',
                      border: OutlineInputBorder(),
                    ),
                  ),
                ),
                const SizedBox(width: 8),
                IconButton.filled(
                  onPressed: _addTask,
                  icon: const Icon(Icons.add),
                ),
              ],
            ),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: Row(
              children: [
                Text(
                  _left == 1 ? '1 task left' : '$_left tasks left',
                  style: Theme.of(context).textTheme.titleSmall,
                ),
              ],
            ),
          ),
          Expanded(
            child: ListView.builder(
              itemCount: _tasks.length,
              itemBuilder: (context, index) {
                final task = _tasks[index];
                return ListTile(
                  leading: Checkbox(
                    value: task.done,
                    onChanged: (value) {
                      setState(() {
                        task.done = value!;
                      });
                    },
                  ),
                  title: Text(
                    task.title,
                    style: task.done
                        ? const TextStyle(
                            decoration: TextDecoration.lineThrough,
                            color: Colors.grey,
                          )
                        : null,
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Progetti

Esercitati da solo: Compilatore Flutter online