Proyek Ketiga: Membuat Aplikasi Todo List Lengkap dengan Fitur Hapus Tugas
Pada proyek terakhir dari seri dasar Flutter ini, kita akan menyempurnakan alur pengolahan data lokal dengan membangun Aplikasi Todo List.
Aplikasi ini tidak hanya menerima input data baru, tetapi juga mengimplementasikan operasi manipulasi data lengkap: menandai tugas yang selesai (update status) dan menghapus tugas dari daftar (delete item).
Konsep Utama yang Diterapkan
-
Model Data kustom: Membuat kelas Dart tersendiri (
TodoItem) untuk memuat properti nama tugas dan status penyelesaiannya secara terstruktur. -
Manipulasi List Dinamis: Memperbarui properti elemen secara spesifik berdasarkan indeksnya, serta menghapus data menggunakan fungsi
List.removeAt(). -
Efek Visual Kondisional: Mengubah gaya teks (text decoration) menjadi dicoret (strikethrough) ketika status tugas dinyatakan selesai.
Kode Lengkap Proyek
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(
debugShowCheckedModeBanner: false,
home: TodoApp(),
));
}
// 1. Model Data untuk Tugas
class TodoItem {
String title;
bool isDone;
TodoItem({required this.title, this.isDone = false});
}
class TodoApp extends StatefulWidget {
const TodoApp({super.key});
@override
State<TodoApp> createState() => _TodoAppState();
}
class _TodoAppState extends State<TodoApp> {
// Penampung data berjenis kustom TodoItem
final List<TodoItem> _todos = [];
final TextEditingController _controller = TextEditingController();
// Menambah tugas baru
void _addTodo() {
final text = _controller.text.trim();
if (text.isNotEmpty) {
setState(() {
_todos.add(TodoItem(title: text));
_controller.clear();
});
}
}
// Mengubah status selesai/belum selesai
void _toggleTodoStatus(int index) {
setState(() {
_todos[index].isDone = !_todos[index].isDone;
});
}
// Menghapus tugas dari list
void _deleteTodo(int index) {
setState(() {
_todos.removeAt(index);
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Todo List Lengkap'),
backgroundColor: Colors.teal,
foregroundColor: Colors.white,
),
body: Column(
children: [
// Form Input Tugas
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: const InputDecoration(
hintText: 'Tambah tugas baru...',
border: OutlineInputBorder(),
),
),
),
const SizedBox(width: 8),
ElevatedButton(
onPressed: _addTodo,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.teal,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: const Text('Tambah'),
),
],
),
),
// Daftar Tugas
Expanded(
child: _todos.isEmpty
? const Center(
child: Text(
'Belum ada tugas. Yey!',
style: TextStyle(color: Colors.grey),
),
)
: ListView.builder(
itemCount: _todos.length,
itemBuilder: (context, index) {
final todo = _todos[index];
return Card(
margin: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 4,
),
child: ListTile(
// Checkbox untuk mengubah status
leading: Checkbox(
value: todo.isDone,
onChanged: (_) => _toggleTodoStatus(index),
),
// Judul tugas dengan gaya kondisional
title: Text(
todo.title,
style: TextStyle(
decoration: todo.isDone
? TextDecoration.lineThrough
: TextDecoration.none,
color: todo.isDone ? Colors.grey : Colors.black,
),
),
// Tombol Hapus
trailing: IconButton(
icon: const Icon(
Icons.delete,
color: Colors.redAccent,
),
onPressed: () => _deleteTodo(index),
),
),
);
},
),
),
],
),
);
}
}
Bedah Jalurnya Kode
-
Penggunaan Class
TodoItem: Memisahkan logika struktur data dari UI. Ini memungkinkan satu item memuat dua informasi sekaligus (titledan statusisDone). -
Toggle Checkbox (
_toggleTodoStatus): KetikaCheckboxdiklik, statusisDonedari item pada indeks tertentu dibalik (!todo.isDone).setState()kemudian memperbarui tampilan teks menjadi dicoret secara otomatis. -
Penghapusan Data (
_deleteTodo): Menggunakan_todos.removeAt(index)untuk menghapus elemen pada indeks spesifik secara efisien.



