To Do App κ΅¬ν˜„_Flutter πŸŽ„

λ°•μ§„Β·2025λ…„ 12μ›” 24일
post-thumbnail

2025.12.24 (수) 과제둜 λ§Œλ“  To Do App κ΅¬ν˜„ 정리 πŸŽ„

λͺ©μ°¨
1. ν”„λ‘œμ νŠΈ μ†Œκ°œ
2. μ£Όμš”κΈ°λŠ₯
3. ν”„λ‘œμ νŠΈ 파일 ꡬ쑰
4. Trouble Shooting



πŸŽ…πŸ» 1. ν”„λ‘œμ νŠΈ μ†Œκ°œ

Flutter 기초 κ³Όμ •μ—μ„œ 배운 λ ˆμ΄μ•„μ›ƒ 섀계 λŠ₯λ ₯을 λ°”νƒ•μœΌλ‘œ μ‹€λ¬΄μ—μ„œ μ‚¬μš©ν•˜λŠ” ν™ˆνŽ˜μ΄μ§€(Home Page), λ°”ν…€μ‹œνŠΈ(Bottom Sheet), λ””ν…ŒμΌ νŽ˜μ΄μ§€ (Detail Page) λ“± νŽ˜μ΄μ§€ κ°„ 데이터 전달 μ‹œμŠ€ν…œμ„ κ΅¬ν˜„ν•˜κ³  직접 app을 ꡬ상 및 κ΅¬μ„±ν•˜κ²Œ ν•΄λ³΄μ•˜λ‹€.


πŸŽ…πŸ» 2. μ£Όμš”κΈ°λŠ₯

πŸ”» 직관적인 νŽ˜μ΄μ§€

  • πŸŽ„ λ©”μΈνŽ˜μ΄μ§€
    AppBar 타이틀에 이름을 μ μš©ν•  수 μžˆλ„λ‘ ν•˜μ—¬ κ°œμΈν™”λœ νŽ˜μ΄μ§€λ₯Ό κ΅¬μ„±ν–ˆμœΌλ©°, webp이미지λ₯Ό λ°°μΉ˜ν•΄μ„œ μš©λŸ‰μ„ μ€„μ—¬μ„œ μ•±μ˜ κΈ°λŠ₯을 μ΅œμ ν™”

  • πŸŽ„ 할일 λͺ©λ‘ νŽ˜μ΄μ§€
    ν•  일 데이터 μœ λ¬΄μ— 따라 'ν•  일 μ—†μŒ' μœ„μ ―κ³Ό '리슀트뷰'λ₯Ό 적용

  • πŸŽ„ 상세 정보 νŽ˜μ΄μ§€
    ToDoEntity 객체λ₯Ό λ„˜κ²¨λ°›μ•„μ„œ 상세 λ‚΄μš©μ„ 화면에 κ΅¬μ„±ν•˜κ³  νŽ˜μ΄μ§€μ™€ 리슀트 νŽ˜μ΄μ§€ κ°„μ˜ 데이터λ₯Ό λ„˜κ²¨λ°›μ„ 수 μžˆλ„λ‘ κ΅¬ν˜„

πŸ”» 슀마트 ν•  일 μΆ”κ°€

  • πŸŽ„ focus μ‹œμŠ€ν…œ
    μΆ”κ°€ μ°½ ν™œμ„±ν™” μ‹œμ— μžλ™ ν¬μ»€μŠ€κ°€ 될 수 μžˆλ„λ‘ κ΅¬μ„±ν•˜μ—¬ ν‚€λ³΄λ“œ λ…ΈμΆœλ‘œ μ‚¬μš©μžκ°€ μž…λ ₯ν•  수 μžˆλ„λ‘ κ΅¬ν˜„

  • πŸŽ„ λ°˜μ‘ν˜• λ ˆμ΄μ•„μ›ƒ
    MediaQueryλ₯Ό μ‚¬μš©ν•΄μ„œ ν‚€λ³΄λ“œκ°€ 올라올 λ•Œ μž…λ ₯창이 κ°€λ €μ§€μ§€ μ•Šλ„λ‘ ν•˜λ‹¨ 여백을 쑰절

  • πŸŽ„ 'μ €μž₯'λ²„νŠΌ ν™œμš©
    ν•  일 제λͺ©μ΄ μž…λ ₯된 κ²½μš°μ—λ§Œ 'μ €μž₯'λ²„νŠΌμ΄ ν™œμ„±ν™” λ˜λ„λ‘ 섀계

πŸ”» μƒνƒœκΈ°λ°˜ 리슀트

  • πŸŽ„ μ•„μ΄μ½˜ 및 μ·¨μ†Œμ„  μ‚¬μš©
    즐겨찾기λ₯Ό ν™œμ„±ν™”ν•΄μ„œ μ‚¬μš©μžκ°€ μ¦κ²¨μ°ΎλŠ” λ‚΄μš©μ„ ν•œ λˆˆμ— 확인 ν•  수 μžˆλ„λ‘ ν–ˆμœΌλ©°, μ²΄ν¬λ°•μŠ€λ₯Ό μ„ νƒν–ˆμ„ λ•Œμ—” ν•  일 제λͺ©μ— μ·¨μ†Œμ„  효과λ₯Ό λ„£μ–΄μ„œ μ‹€μ‹œκ°„μœΌλ‘œ μƒνƒœλ₯Ό 확인 ν•  수 μžˆλ„λ‘ ν–ˆλ‹€.

  • πŸŽ„ Home Page와 Detail page 연동
    ν•  일이 없을 κ²½μš°μ— μ‚¬μš©μžμ—κ²Œ ν•  일 λͺ©λ‘μ„ μž‘μ„±ν•˜λΌκ³  μœ„μ ―μ„ ν‘œμ‹œν•˜κ³ , ν•  일 λͺ©λ‘μ΄ μžˆμ„ κ²½μš°μ—λŠ” 리슀트λ₯Ό ν•œ λˆˆμ— λ³Ό 수 μžˆλ„λ‘ 화면을 λ…ΈμΆœμ‹œν‚€λ„λ‘ κ΅¬ν˜„ν–ˆλ‹€.

  • πŸŽ„ ν…μŠ€νŠΈ μž…λ ₯ μ œν•œ
    ν•  일 제λͺ©μ—λŠ” ν…μŠ€νŠΈ μ œν•œμ„ λ‘¬μ„œ 제λͺ©μ„ ν•œ λˆˆμ— λ³Ό 수 있게 κ΅¬ν˜„ν–ˆμœΌλ©°, 상세 ν…μŠ€νŠΈμ—λŠ” κΈ€μžκ°€ κΈΈμ–΄μ§€λ©΄ μžλ™μœΌλ‘œ μ€„λ°”κΏˆμ΄ 될 수 μžˆλ„λ‘ μ μš©ν–ˆλ‹€.


πŸŽ…πŸ» 3. ν”„λ‘œμ νŠΈ 파일 ꡬ쑰

πŸ“¦lib
 ┣ home
 ┃ ┣ widgets
 ┃ ┃ β”— add_todo_bottom_sheet.dart
 ┃ β”— home_page.dart
 ┣ todo_detail
 ┃ ┣ widgets
 ┃ ┃ ┣ to_do_view.dart
 ┃ ┃ β”— todo_entity.dart
 ┃ β”— detail_page.dart
 β”— main.dart

πŸŽ…πŸ» 4. Troble Shooting

πŸ”» TextField λ ˆμ΄μ•„μ›ƒ μ˜€λ²„ν”Œλ‘œμš° 문제

🀢🏻 문제
상세 μ„€λͺ… μž…λ ₯창에 maxLines: null을 μ„€μ •ν•˜μž, ν…μŠ€νŠΈκ°€ κΈΈμ–΄μ§ˆ λ•Œ λΆ€λͺ¨ μœ„μ ―μ˜ λ²”μœ„λ₯Ό λ²—μ–΄λ‚˜μ„œ μ˜€λ²„ν”Œλ‘œμš°κ°€ λ°œμƒν–ˆμ—ˆλ‹€.

🀢🏻 원인
λ¬΄ν•œνžˆ λŠ˜μ–΄λ‚  수 μžˆλŠ” TextFieldκ°€ 크기 μ œν•œμ΄ μ—†λŠ” Row/Column μ•ˆμ— μœ„μΉ˜ν–ˆκΈ° λ•Œλ¬Έμ΄μ—ˆλ‹€.

πŸ§‘πŸ»β€πŸŽ„ ν•΄κ²°
TextFieldλ₯Ό Flexible μœ„μ ―μœΌλ‘œ κ°μ‹Έμ„œ λΆ€λͺ¨ 내에 μ‚¬μš© κ°€λŠ₯ν•œ κ³΅κ°„λ§Œ μ°¨μ§€ν•˜κ³ , λ‚΄μš©μ΄ λ§Žμ•„μ§€λ©΄ 남은 κ³΅κ°„λ§Œ μ‚¬μš©ν•  수 μžˆλ„λ‘ λŠ˜μ–΄λ‚¬λ‹€.

πŸ”» setState와 StatefulWidget

🀢🏻 문제
ν•  일 λ¦¬μŠ€νŠΈμ— ν•­λͺ©μ„ μΆ”κ°€ν–ˆμœΌλ‚˜, μ•„μ΄μ½˜μ„ 체크해도 ν™”λ©΄μ—λŠ” μ•„λ¬΄λŸ° λ³€ν™”κ°€ μ—†μ—ˆμŠ΅λ‹ˆλ‹€. setStateλ₯Ό μ“°λ €λ©΄ The method 'setState' ins't defined λΌλŠ” μ—λŸ¬κ°€ λ°œμƒν–ˆλ‹€.

🀢🏻 원인
StatelessWidget은 μ‚¬μš©ν•˜κ²Œ 되면 화면을 λ°”κΏ€ 수 μ—†λŠ” μœ„μ ―μœΌλ‘œ ν™”λ©΄μ˜ 일뢀가 μ‚¬μš©μžμ˜ λ™μž‘μœΌλ‘œ λ³€ν•˜κ²Œ 될 μ‹œμ—λŠ” λ°˜λ“œμ‹œ StatefulWidget을 μ‚¬μš©ν•΄μ•Ό ν–ˆλ‹€.

πŸ§‘πŸ»β€πŸŽ„ ν•΄κ²°
μœ„μ ―μ„ StatefulWidet으둜 λ³€κ²½ν•˜κ³ , 데이터가 λ³€κ²½λ˜λŠ” μ‹œμ μ— setState()λ₯Ό ν˜ΈμΆœν•˜κ²Œ ν•΄μ„œ 데이터 변화에 따라 ν™”λ©΄ λ³€ν™”λ₯Ό 쀄 수 μžˆμ—ˆλ‹€.

πŸ”» titleController.addListener

🀢🏻 문제
ν•  일 제λͺ©μ„ μž…λ ₯ν•˜μ§€ μ•Šμ•˜μ„ λ•Œλ„ 'μ €μž₯'λ²„νŠΌμ΄ ν™œμ„±ν™” λ˜λŠ” λ¬Έμ œκ°€ μžˆμ—ˆλ‹€.

🀢🏻 원인
TextField에 κΈ€μžκ°€ 써지고 μ§€μ›Œμ§€λŠ” 것을 μ‹€μ‹œκ°„μœΌλ‘œ 확인 ν•  수 μžˆλŠ” κΈ°λŠ₯이 ν•„μš”ν–ˆλ‹€.

πŸ§‘πŸ»β€πŸŽ„ ν•΄κ²°
TextFieldμ—μ„œ addListenerκΈ°λŠ₯을 ν™œμš©ν•˜κ³  initStateμ—μ„œ λ¦¬μŠ€λ„ˆλ₯Ό μ‚¬μš©, μ‚¬μš©μžκ°€ κΈ€μžλ₯Ό 치게되면 canSave λ³€μˆ˜λ₯Ό μ—…λ°μ΄νŠΈ ν•˜λ„λ‘ ν•΄μ„œ 문제λ₯Ό ν•΄κ²°ν–ˆλ‹€.

@override
void initState() {
  super.initState();
  titleController.addListener(() {
    setState(() {
      canSave = titleController.text.isNotEmpty;
    });
  });
}

πŸ”» μœ„μ ― 뢄리와 객체 λ„˜κΈ°κΈ°

🀢🏻 문제
μ½”λ“œκ°€ λ„ˆλ¬΄ κΈΈμ–΄μ§€κΈ° μ‹œμž‘ν•˜λ©΄μ„œ ToDoViewλ‚˜ AddTodoBottomSheetλ₯Ό λ³„λ„μ˜ 파일둜 λΆ„λ¦¬ν–ˆλ”λ‹ˆ HomePage에 μžˆλŠ” 데이터λ₯Ό 찾을 수 μ—†λ‹€λŠ” μ—λŸ¬κ°€ λ§Žμ•„μ Έμ„œ λ‹Ήν™©ν–ˆμ—ˆλ‹€.

🀢🏻 원인
파일둜 λΆ„λ¦¬λ˜λ©΄μ„œ μœ„μ ―μ΄ λ–¨μ–΄μ§€κ²Œ 되고, 데이터λ₯Ό μ‚¬μš©ν•˜λ €λ©΄ μƒμ„±μžλΌλŠ” 것을 톡해 데이터λ₯Ό λ„˜κ²¨μ€˜μ•Ό ν–ˆλ‹€.

πŸ§‘πŸ»β€πŸŽ„ ν•΄κ²°
객체 전달과 ν•¨μˆ˜ 전달

  • 객체 전달: ToDoViewκ°€ TodoEntity 전체λ₯Ό 받을 수 μžˆλ„λ‘ final TodoEntity toDo;λ₯Ό μ„ μ–Έν•˜κ³  requiredν‚€μ›Œλ“œλ‘œ λ°›μ•„μ„œ ν•΄κ²°ν–ˆλ‹€.

  • ν•¨μˆ˜ 전달: 상세 νŽ˜μ΄μ§€λ‚˜ μžμ‹ μœ„μ ―μ—μ„œ λΆ€λͺ¨μ˜ μƒνƒœλ₯Ό λ°”κΎΈλ €λ©΄ ν•¨μˆ˜ 자체λ₯Ό μ „λ‹¬ν•΄μ„œ μ½œλ°±ν•˜λŠ” 방식이 ν•„μš”ν–ˆμŠ΅λ‹ˆλ‹€. final VoidCallback onToggleDone;처럼 ν•¨μˆ˜λ₯Ό λ³€μˆ˜λ‘œ λ„˜κ²¨μ£ΌλŠ” 방식을 μ‚¬μš©ν•˜μ—¬ ν•΄κ²°ν–ˆλ‹€.

πŸ”» final λ³€μˆ˜

🀢🏻 문제
todo.isDone = !todo.isDone; μ½”λ“œλ₯Ό μΌλŠ”λ° μ—λŸ¬κ°€ λ°œμƒν–ˆλ‹€. can't be used as a setter because it's final

🀢🏻 원인
TodoEntity ν΄λž˜μŠ€μ—μ„œ λ³€μˆ˜λ“€μ„ final둜 μ„ μ–Έν–ˆκΈ°μ— λ³€ν•˜μ§€ μ•ŠλŠ” κ°’μœΌλ‘œ μΈμ‹λ˜μ–΄ μˆ˜μ •μ΄ λΆˆκ°€λŠ₯ν–ˆλ˜ κ²ƒμœΌλ‘œ ν™•μΈν–ˆλ‹€.

πŸ§‘πŸ»β€πŸŽ„ ν•΄κ²°
μƒνƒœκ°€ λ³€ν•  수 μžˆλ„λ‘ final ν‚€μ›Œλ“œλ₯Ό μ œκ±°ν•˜κ³  λ³€κ²½ κ°€λŠ₯ν•œ μƒνƒœλ‘œ λ§Œλ“€μ—ˆλ‹€.


ν”„λ‘œμ νŠΈλ₯Ό 마치며... πŸŽ„πŸŽ„πŸ€ΆπŸ»πŸŽ…πŸ»πŸ§‘πŸ»β€πŸŽ„πŸŽ„πŸŽ„

이번 ν”„λ‘œμ νŠΈλ₯Ό 톡해 λ°μ΄ν„°λŠ” 객체 전달과 ν•¨μˆ˜ 전달, μœ„μ ―μ˜ μœ„μΉ˜ λ“±μ˜ 핡심 원리가 μ€‘μš”ν•˜λ‹€λŠ” 사싀을 κΉ¨λ‹«κ²Œ ν•΄μ£Όμ—ˆμœΌλ©°, λ¨Έλ¦¬μ†μœΌλ‘œλŠ” 이해가 λ˜λŠ”λ° μ‘°κΈˆμ€ ꡬ쑰적인 λΆ€λΆ„μ—μ„œ 도움이 될 수 μžˆμ—ˆλ˜ ν”„λ‘œμ νŠΈ μ˜€λ‹€..


λ„ˆλ¬΄λ‚˜ λ§Žμ•˜λ˜ 였λ₯˜.. νŠΈλŸ¬λΈ”μŠˆνŒ…μ— μ“°κΈ°μ—” 캑쳐 λ‚΄μ—­κ³Ό 정리 내역이 λ’€μ£½λ°•μ£½ 찾기도 μ–΄λ €μ› λ‹€..γ…Ž 캑쳐 내역은 훨씬 λ§Žλ‹€λŠ” 사싀~! 였λ₯˜λ‚˜ μ—λŸ¬κ°€ λ‚˜λ©΄ 정리할 μ‹œκ°„λ„ 없이 잘 λͺ» 되면 μ–΄μ©Œμ§€λž€ λ§ˆμŒμ— κΈ‰ν•˜κ²Œ μ²˜λ¦¬ν•˜λ‹€λ³΄λ‹ˆ 정리할 μ‹œκ°„μ΄ 많이 μ—†μ—ˆλ‹€..γ… 

이번 To Do App은 μ €μ—κ²ŒλŠ” 아직은 λ„ˆλ¬΄ μ–΄λ €μš΄ ν”„λ‘œμ νŠΈμ˜€λ˜ 것 κ°™λ‹€. 거의 1년은 μ§€λ‚œ λŠλ‚Œ.. 완성은 ν–ˆμœΌλ‚˜ κ·Έλ•Œ κ·Έλ•Œμ˜ μ—λŸ¬μ— μœ μ—°ν•˜μ§€ λͺ» ν•˜κ²Œ 당황을 λ§Žμ΄ν•˜κ³  λŒ€μ‘ν–ˆλ˜κ²Œ 아쉽고 κΌ­ λ‹€μ‹œ λ§Œλ“€μ–΄λ³΄κ³  λ³΅μŠ΅ν•˜λŠ” μ‹œκ°„μ΄ ν•„μš”ν•˜λ‹€κ³  λŠκΌˆλ‹€.

0개의 λŒ“κΈ€