할 일 목록 앱을 만들었다면, 이제 중요한 기능 하나가 남았습니다.
바로, 완료된 항목을 체크하거나 해제할 수 있는 기능입니다.
이번 글에서는 Flutter 앱에 Checkbox 위젯을 적용하여 할 일 항목에 상태(완료/미완료)를 표시하는 방법을 알려드립니다.
🧩 어떤 기능을 추가할까요?
✅ 각 할 일 항목 옆에 체크박스 표시
✅ 체크하면 완료 → 텍스트에 취소선 적용
✅ 체크 해제 시 다시 미완료 상태로 변경
🛠️ 구조 변경 – String 대신 Map으로 관리
기존에는 List<String>으로만 할 일을 저장했지만,
완료 상태를 저장하려면 Map 형태로 구조를 바꿔야 합니다.
dart
복사편집
List<Map<String, dynamic>> _todoList = [ {'title': 'Flutter 공부', 'done': false}, {'title': '운동하기', 'done': true}, ];
💻 전체 코드 예제 (check 기능 포함)
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: TodoCheckboxApp()));
class TodoCheckboxApp extends StatefulWidget {
@override
_TodoCheckboxAppState createState() => _TodoCheckboxAppState();
}
class _TodoCheckboxAppState extends State<TodoCheckboxApp> {
final TextEditingController _controller = TextEditingController();
List<Map<String, dynamic>> _todoList = [];
void _addTodo() {
String text = _controller.text.trim();
if (text.isNotEmpty) {
setState(() {
_todoList.add({'title': text, 'done': false});
_controller.clear();
});
}
}
void _toggleDone(int index) {
setState(() {
_todoList[index]['done'] = !_todoList[index]['done'];
});
}
void _removeTodo(int index) {
setState(() {
_todoList.removeAt(index);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('할 일 체크 앱')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// 입력창 + 추가 버튼
Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: InputDecoration(
labelText: '할 일을 입력하세요',
border: OutlineInputBorder(),
),
),
),
SizedBox(width: 10),
ElevatedButton(
onPressed: _addTodo,
child: Text('추가'),
),
],
),
SizedBox(height: 20),
// 리스트
Expanded(
child: ListView.builder(
itemCount: _todoList.length,
itemBuilder: (context, index) {
final item = _todoList[index];
return Card(
child: ListTile(
leading: Checkbox(
value: item['done'],
onChanged: (_) => _toggleDone(index),
),
title: Text(
item['title'],
style: TextStyle(
decoration: item['done']
? TextDecoration.lineThrough
: TextDecoration.none,
),
),
trailing: IconButton(
icon: Icon(Icons.delete, color: Colors.red),
onPressed: () => _removeTodo(index),
),
),
);
},
),
),
],
),
),
);
}
}
void main() => runApp(MaterialApp(home: TodoCheckboxApp()));
class TodoCheckboxApp extends StatefulWidget {
@override
_TodoCheckboxAppState createState() => _TodoCheckboxAppState();
}
class _TodoCheckboxAppState extends State<TodoCheckboxApp> {
final TextEditingController _controller = TextEditingController();
List<Map<String, dynamic>> _todoList = [];
void _addTodo() {
String text = _controller.text.trim();
if (text.isNotEmpty) {
setState(() {
_todoList.add({'title': text, 'done': false});
_controller.clear();
});
}
}
void _toggleDone(int index) {
setState(() {
_todoList[index]['done'] = !_todoList[index]['done'];
});
}
void _removeTodo(int index) {
setState(() {
_todoList.removeAt(index);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('할 일 체크 앱')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// 입력창 + 추가 버튼
Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: InputDecoration(
labelText: '할 일을 입력하세요',
border: OutlineInputBorder(),
),
),
),
SizedBox(width: 10),
ElevatedButton(
onPressed: _addTodo,
child: Text('추가'),
),
],
),
SizedBox(height: 20),
// 리스트
Expanded(
child: ListView.builder(
itemCount: _todoList.length,
itemBuilder: (context, index) {
final item = _todoList[index];
return Card(
child: ListTile(
leading: Checkbox(
value: item['done'],
onChanged: (_) => _toggleDone(index),
),
title: Text(
item['title'],
style: TextStyle(
decoration: item['done']
? TextDecoration.lineThrough
: TextDecoration.none,
),
),
trailing: IconButton(
icon: Icon(Icons.delete, color: Colors.red),
onPressed: () => _removeTodo(index),
),
),
);
},
),
),
],
),
),
);
}
}
🔍 주요 기능 요약
기능설명
| Checkbox | 완료 상태 체크/해제 |
| Map<String, dynamic> | 항목에 title, done 정보 포함 |
| TextDecoration.lineThrough | 완료 항목에 취소선 표시 |
| setState() | 상태 변화 시 UI 자동 갱신 |
💡 사용자 경험 향상 팁
- done == true일 때 텍스트를 회색으로 처리하면 가시성 ↑
- 완료된 항목은 리스트 맨 아래로 정렬하는 것도 UX적으로 유용
- 장기적으로는 로컬 DB(Firebase, SharedPreferences 등) 연동으로 데이터 유지도 고려해보세요
🧠 마무리 요약
기능구현 방법
| 할 일 완료 표시 | Checkbox + done 상태 |
| UI 반영 | 텍스트에 lineThrough 적용 |
| 상태 갱신 | setState()로 업데이트 |
이제 여러분의 할 일 앱은 더 이상 "읽기 전용"이 아닙니다.
진짜로 쓰고 지우고 체크할 수 있는 유용한 앱이 된 거예요!