Danh sách việc cần làm: Hoàn tác xóa
Thuộc phần Dự án trong hành trình Flutter của Coddy. Bài học 7 trên 36.
Một thao tác vuốt diễn ra nhanh, và vuốt nhầm cũng vậy. Ứng dụng tốt cho phép bạn hoàn tác: một thông báo ở cuối màn hình cho biết mục nào đã bị xóa, kèm nút Hoàn tác bên cạnh.
SnackBar nhận action:, một SnackBarAction có label và onPressed. Để đưa tác vụ về vị trí cũ, hãy ghi nhớ vị trí của nó trước khi xóa:
final index = _tasks.indexOf(task);
// Xóa tác vụ đó, rồi hiển thị SnackBar
SnackBarAction(
label: 'Undo',
onPressed: () {
setState(() {
_tasks.insert(index, task);
});
},
)Vuốt nhanh hai tác vụ thì thông báo thứ hai sẽ chờ đến khi thông báo đầu tiên hết thời gian hiển thị. Gọi ScaffoldMessenger.of(context).hideCurrentSnackBar(); trước showSnackBar để thông báo mới nhất hiện ngay lập tức.
insert(index, task) đưa tác vụ về vị trí đó và đẩy các tác vụ phía sau xuống. add sẽ đưa tác vụ vào cuối danh sách.
Hàm bạn truyền cho onPressed ghi nhớ index và task tại thời điểm bạn tạo hàm, dù hàm chạy sau đó. Đó là một closure, và callback luôn dựa vào nó.
Thử thách
Trung bìnhCho phép hoàn tác thao tác xóa. Trong _deleteTask:
- trước khi xóa công việc, lưu lại vị trí của nó bằng
indexOf - sau khi xóa, hiển thị
SnackBarvới nội dungDeletedvà tiêu đề công việc, chẳng hạn nhưDeleted Walk the dog - thêm thao tác
Undođể đưa công việc trở lại vị trí cũ - ẩn thông báo đang hiển thị trước, để thao tác xóa mới thay thế thông báo đó
Tự làm thử
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,
),
),
);
},
),
),
],
),
);
}
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Dự án
1Dự án: Danh sách việc cần làm
Danh sách việc cần làm: Danh sách công việcDanh sách việc cần làm: Thêm công việc4Dự án: Theo dõi thói quen
Theo dõi thói quen: Thói quen của bạnTheo dõi thói quen: TuầnTự luyện tập: Trình biên dịch Flutter online