To-Do List 앱 Step 7. 완료/미완료 분리 표시 및 필터 기능 추가

2024. 12. 4. 18:18같이 공부합시다 - Flutter/Flutter로 To-Do 앱 만들기

728x90
반응형

 
두둥 !
이번엔 이전 내용에 이어지는 기능입니다.
 
이제 우리는 완료/미완료 체크를 구분할 수 있으므로,
그에 따른 필터 기능을 추가할 수 있습니다 !
 
좋아요 ! 멋집니다 !
 
우리 많이 왔네요 : )
이제 이름을 좀 바꿔 봅시다.
대부분 기능 추가에 따른 챕터가 생겼으니까,
 
할 일 목록입니다. 가 아닌
기능 추가 목록입니다. 😁
 
3 . 화면에 할 일 리스트 표시.
4 . 할 일 삭제 기능 추가
5 . 데이터 저장 추가
6 . 항목 완료 체크 기능 추가
7 . 완료/미완료 분리 표시 및 필터 기능 추가
8 . 할 일 목록 수정 기능 추가
9 . 완료된 항목을 자동으로 삭제하는 옵션 추가


 
자, 오늘의 주요 기능은 ‘필터링’입니다.
필터링 기능을 구현하기 위한 오늘의 할 일 입니다 : )
 

  1. 팝업 메뉴 버튼 추가하기
  2. 필터 상태값 만들기
  3. PopupMenuButton 메뉴에 필터 상태값 추가
  4. 필터된 리스트를 담아둘 수 있는 변수 만들기
  5. _getFilteredTodos() 메서드 만들기
  6. 앱 화면에 필터된 리스트 보여주기

메뉴 버튼을 하나 만들어서 필터링 해봅시다 : )


<필터링 이미지>

필터링 !


1) 팝업 메뉴 버튼 추가하기

 
필터링 할 수 있는 메뉴는 AppBar
그러니까 To-Do List 제목이 있는
위치에 메뉴 버튼을 추가해 봅시다.


<기존 AppBar>


<PopupMenuButton 추가>


1-1) actions : [ PopupMenuButton () ]

 
AppBar 의 속성인 actions 에,
PopupMenuButton 을 추가합시다.
( actions 속성에서는 정말 많은 기능이 있어요. 😅 )
 
이전에 FloatingButton 만들 때가 엊그제 같은데,
벌써 시간이 좀 지났네요 (ㅎ)
 
2024.11.23 - [Develog/Flutter] - To-Do List 앱 Step 2-0. 플로팅버튼 띄우기

To-Do List 앱 Step 2-0. 플로팅버튼 띄우기

서론이 너무 길었다.이제 드디어 기능을 넣어 볼 차례다. 두근두근 거리는구만. 구현하려는 내용은 다음과 같다.1. 화면 오른쪽 아래에 “+ (할 일 추가)” 플로팅 버튼 만들기.2. 플로팅 버튼을

steadybuilder.tistory.com

 

 


1-2) itemBuilder: (context) => [ ]

 
여기에서는 다이얼로그와 유사한
itemBuilder 속성이 필요합니다.
(다이얼로그에서는 builder 속성 사용)
 
2024.11.24 - [Develog/Flutter] - To-Do List 앱 Step 2-1. 플로팅버튼 > 다이얼로그 기본 호출 구조

To-Do List 앱 Step 2-1. 플로팅버튼 > 다이얼로그 기본 호출 구조

[ 만들어 보려는 내용 ]1 . 화면 오른쪽 아래에 “+ (할 일 추가)” 플로팅 버튼 만들기.2-1. 플로팅 버튼을 눌렀을 때 다이얼로그가 열리고, 사용자가 할 일을 입력할 수 있음.2-2. ‘취소’ 텍스트

steadybuilder.tistory.com

 

  
builder 나 itemBuilder 는 앱 화면 안에서
일정 부분의 팝업을 만들어주는 역할을 합니다.
 
itemBuilder 또한
BuildContext context
매개변수로 받아서,
화면에 뿌려줄 메뉴 항목 리스트를
만들어 줍니다.
 
참고로, 플러터는 타입 정보를 많이 생략하기 때문에,
(context) 로만 사용해도 오류가 발생되지 않아요.
 
이 [ ] 안에는 눈으로 볼 메뉴 항목을 설정하면 됩니다.
 


<PopupMenuButton 추가 결과>


전체 보기 외에 ‘완료 보기’ ,
그리고 ‘미완료 보기’ 도 추가해야겠죠 ?


<PopupMenuButton 메뉴 추가>


좋아요 ! 그럴듯해졌죠 ?
메뉴만 만들어진 것 뿐,
아직은 동작하지 않습니다.

이제 동작되도록 해야죠 !
 
 
 


 

2) 필터 상태값 만들기

 
필터를 하기 위해서는,
기준이 되는 플래그 값이 필요합니다.
즉, 필터 상태값을 말하죠.
 
앞에서 만든 PopupMenuButton 메뉴 중 하나를
선택했을 때, 필터 상태값이 바뀔 수 있도록 하는거죠.


<필터 상태값 만들기>


_todoList 완료 상태값은
isCompleted 의
true / false 로 구분했죠.

필터는 completed(완료) , active(미완료) ,
all(전체)로 구분합시다.

_filter 변수에 초기값은
all(전체)로 설정할게요.
 
 
 


 

3) PopupMenuButton 메뉴에 필터 상태값 추가

 
아까 만들어 둔 팝업 메뉴에서,
메뉴를 터치했을 때 필터 상태값이 변하도록 해봅시다.
그럴려면 각 메뉴 별 상태에 대한 값을 가져야겠죠.


<PopupMenuButton 메뉴에 필터 상태값 추가>


🔸PopupMenuButton(value…
각 메뉴에 value 로 구분값을 주었습니다.
value 를 child 뒤에 두려니 경고가 뜨네요,
앞으로 옮기라고 (ㅎ) 뭐 , 권장 규격에 맞춥시다.
 
🔸onSelected:
테스트를 위해 메뉴를 선택했을 때마다
콘솔에 남기도록 했습니다.
 
하나씩 메뉴를 눌러보면
value 값을 잘 받아오는 것을 볼 수 있습니다.
 
굿굿 !
 
이제 이 value 값이 필터 상태값으로
만들어 둔 _filter 를 바꾸면 되겠군요.


<PopupMenuButton의 메뉴 클릭 시 필터 상태값 변경>


🔸setState()
사용자가 PopupMenuButton의 메뉴를 클릭했을 때,
실시간으로 value의 값이 _filter 에 적용되어야만,
이후에 body 에서 실시간으로
출력되는 항목을 변경할 수 있어요.
 
이제 우리는 필터 메뉴에서 상태값까지
실시간으로 변경할 수 있도록 만들었어요.
 
이제 뭐하면 될까요 ?
맞습니다. 필터에 따라 화면 뿌려주면 되겠죠 !
 
 
 


 

4) 필터된 리스트를 담아둘 수 있는 변수 만들기

 
자, 여기서부터는 집중해서 따라오셔야 합니다.
생각보다 복잡하거든요.
 

 
아시죠? 그래도 가봅시다 !
 
현재 화면에 뿌려주도록 되어 있는 값은
final todoItem = _todoList[index]; 입니다.
 
List 인 _todoList 의 index,
그러니까 0,1,2 .. 에 따라 저장된 정보를 가져오죠.
 
지금 제 _todoList 는 이렇습니다.


<스테디빌더의 _todoList>


여기에서 _todoList[0] 을 출력하면,
{task: 1. _todoList 를 Map 형태로 변경하기, isCompleted: true},
값을 확인할 수 있습니다.
 
그리고 현재 우리 앱은 이렇게 _todoList 에 있는
모든 할 일이 화면에 뿌려지는 중이죠.
 
하지만 이제는 body 에 필터가 된
리스트를 불러올 필요가 있게 되었습니다.
 
이제 필터 상태값(_filter)에 따라서
필터링된 리스트를 담아둘 수 있도록 만들어 봅시다.


<필터된 리스트를 담아둘 수 있는 변수 만들기>


build () 아래 바로 필터된 리스트를
받아올 수 있도록 했습니다.

음? 왜 body 에 있지 않고 여기에 있냐구요?
맞습니다. 기존에 있던 위치랑 다르죠.


<기존에 할 일 목록을 뿌려주는 코드>


<기존 위치와 현재 위치 차이>


이유는 이후에 알려드리겠지만,
body 속성에서도 필터된 리스트가
필요하기 때문입니다.
 
body: _todoList.isEmpty
코드의 조건을 필터된 항목의 리스트가
비어있는지를 체크해야 하기 때문이예요.
 
ListView.builder 안에 지역변수로 있다면
body 속성에서는 사용하지 못할테니까요.
 
자자, 지금 이해가 안된다면 일단 넘어갑시다.
계속 보다보면 이해됩니다 : )
 

 
_getFilteredTodos() 메서드를 호출했으니,
이제 이 메서드를 만들어 볼까요?




5) _getFilteredTodos() 메서드 만들기


<_getFilteredTodos() 메서드 만들기>


_filter 값이 ‘active’ 이면 완료되지 않은 할 일이죠.
 
_todoList.where( ) 메서드는
List 클래스에 포함된 메서드로
특정 조건을 만족하는 항목만
걸러내는 역할을 합니다.
 
여기에서 (item) 은 _todoList 의 각 요소를 의미하고,
toList() 메서드를 통해 새로운 리스트로 변환합니다.
 
where 메서드의 반환값은
List 가 아닌 Iterable 이기 때문에,
리스트로 변환이 필요합니다.
 
정리하면,

_todoList 항목(item) 중에서
isCompleted 의 값이 false ,
그리고 다음 줄은 true 인 것을 찾아서 ,
리스트로 변환하여
새로운 리스트를 얻게 되는거죠 !
 
if else 에 걸리지 않는다면
자연스레 all 이 됩니다.
 
노파심에 하나 덧붙이자면,
where 메서드는 조건이
true 인 항목만 필터링 합니다.
 
따라서, !item[’isCompleted’] 코드는
항목중에 isCompleted 가
false 인 항목만을 필터링 하는거죠.
 
좋습니다.
여기까지 이해 됐어요 !




6) 앱 화면에 필터된 리스트 보여주기

드디어 마지막 작업입니다 !
조금만 더 힘을 내세요 : )
 

 
final filteredTodos = _getFilteredTodos();
방금 만들어 둔 메서드를 통해,
이제 필터 상태값 value 에 따라
완료 , 미완료 , 전체 리스트를
filteredTodos 에
담아둘 수 있게 되었어요.
 
좋습니다 !
이제 body 에서 직접 _todoList 의
항목을 뿌려주는 부분을,
전부 filteredTodos 로 바꿔줘야 합니다.


<filteredTodos 로 변경하기>


6-1) body: filteredTodos.isEmpty

전체 항목이 아닌 필터된 항목이
비어있을 때로 조건을 바꾸었습니다.

6-2) itemCount: filteredTodos.length

전체보기, 완료보기, 미완료보기
모두 필터된 상태로 보여지기 때문에,
itemCount 또한 filteredTodos 를 설정합니다.

6-3) final todoItem = filteredTodos[index]

기존 _todoList 에 접근하던 녀석을
filteredTodos 리스트에 접근하도록 바꿉니다.
이 녀석을 뿌려주게 되죠 : )

6-4) final actualIndex = _todoList.indexOf(todoItem)

actualIndex 는
실제 _todoList 의 값을
변경하기 위해섭니다.

지금의 todoItem 은
필터된 리스트의 인덱스를
가지고 있기 때문이죠.

actualIndex 는
완료 체크나 삭제 시에 사용됩니다.


자, 다 됐습니다 !
이제 마무리 테스트만 남았네요 : )
 

 
완료 보기 ! 쾅 !
미완료 보기 ! 쾅 !
전체 보기 ! 쾅 !
 


<오늘의 결과>


굿 !
 
이 상태에서 미완료 항목의 체크박스를 체크하면 ?
짜잔. 미완료 항목에서는 없어지고
완료 항목에서 확인 가능 !
 
고생하셨습니다 !
끝 !

728x90
반응형