To-do-Liste: Löschen rückgängig machen
Teil des Abschnitts Projekte der Flutter-Journey von Coddy. Lektion 7 von 36.
Ein Wisch ist schnell erledigt – und ein versehentlicher Wisch ebenso. Gute Apps lassen dich den Vorgang rückgängig machen: Unten erscheint eine Meldung, die angibt, was gelöscht wurde, daneben eine Schaltfläche zum Rückgängigmachen.
Ein SnackBar erhält ein action:, eine SnackBarAction mit einem label und einem onPressed. Damit die Aufgabe an ihre ursprüngliche Position zurückkommt, merke dir ihre Position, bevor du sie entfernst:
final index = _tasks.indexOf(task);
// Entferne es und zeige dann die SnackBar an
SnackBarAction(
label: 'Undo',
onPressed: () {
setState(() {
_tasks.insert(index, task);
});
},
)Wenn du zwei Aufgaben schnell hintereinander wegwischst, wartet die zweite Meldung, bis die erste ausgeblendet wird. Rufe ScaffoldMessenger.of(context).hideCurrentSnackBar(); vor showSnackBar auf, damit die neueste Meldung sofort erscheint.
insert(index, task) fügt die Aufgabe an dieser Position wieder ein und verschiebt die nachfolgenden Aufgaben nach unten. add würde sie ans Ende setzen.
Die Funktion, die du an onPressed übergibst, merkt sich index und task von dem Zeitpunkt, an dem du sie erstellt hast, auch wenn sie erst später ausgeführt wird. Das nennt man Closure, und Callbacks nutzen das ständig.
Aufgabe
MittelMache das Löschen rückgängig. In _deleteTask:
- speichere vor dem Entfernen der Aufgabe ihre Position mit
indexOf - zeige nach dem Entfernen eine
SnackBarmit dem TextDeletedund dem Titel der Aufgabe an, zum BeispielDeleted Walk the dog - füge eine Aktion
Undohinzu, die die Aufgabe an ihre alte Position zurücksetzt - blende zuerst die angezeigte Nachricht aus, damit ein neues Löschen sie ersetzt
Probier es selbst
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();
}
void _deleteTask(Task task) {
setState(() {
_tasks.remove(task);
});
}
@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 Dismissible(
key: ObjectKey(task),
direction: DismissDirection.endToStart,
background: Container(
color: Colors.red,
alignment: Alignment.centerRight,
padding: const EdgeInsets.symmetric(horizontal: 24),
child: const Icon(Icons.delete, color: Colors.white),
),
onDismissed: (direction) => _deleteTask(task),
child: 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,
),
),
);
},
),
),
],
),
);
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Projekte
1Projekt: To-do-Liste
To-do-Liste: Die AufgabenlisteTo-do-Liste: Eine Aufgabe hinzufügen4Projekt: Gewohnheitstracker
Gewohnheitstracker: Deine GewohnheitenGewohnheitstracker: Die WocheÜbe selbstständig: Online-Flutter-Compiler