본문 바로가기
프로그래밍/Flutter

[flutter 상태관리] 6. stateful widget 실습2, 태그 필터 갤러리 만들기

by 신나요 2022. 6. 6.

상태 관리 관점에서 stateful widget 실습을 하고 있습니다. sateful widget 실습 1에서 체크박스로 선택 가능한 갤러리를 만들었는데요. 이 화면을 개선해서 태그로 필터 기능을 가지는 갤러리로 수정해 보도록 하겠습니다.

 

*이번 실습을 통해서 배우는 것

1. GridView

2. where 활용법 (자바스크립트의 filter)

4. 상위 위젯에서 하위 위젯으로 상태와 콜백 메소드 건네주기

5. 갤러리 만들기

6. Drawer


지난 앱의 상태

지난 포스트에서 만든 앱은 아래와 같은 화면을 가지고 있습니다.

체크박스를 가지는 갤러리

갤러리는 사진을 단순히 보여주는 일반모드와, 사진을 길게 클릭했을 때 체크박스로 선택을 할 수 있는 태그 모드가 있습니다. 사진의 체크박스를 선택하면 선택된 상태는 로컬 상태에 저장됩니다. 자세한 내용은 아랫글 참고해 주세요.

[flutter 상태관리] 5. stateful widget 실습, 체크박스를 가진 갤러리 만들기

 

이제 아래와 같은 기능을 추가하려고 합니다.

1. 태그 목록을 가지는 서랍(Drawer)을 추가.

2. 일반 모드에서 Drawer에 나오는 태그 목록으로 사진을 필터 해서 보여주는 기능 추가.

3. 태그 모드에서 체크박스로 선택한 사진을 Drawer에서 태그를 선택함으로 사진에 태그 데이터 설정.

코딩을 하기전에는 무엇을 해야 할지 명확히 하는 연습을 하는 것이 중요한 것 같습니다.  물론 실제 업무현장에서는 설계서를 작성한 후에 코딩을 하게 되니깐 어느 정도 명확한 상태에서 코딩을 하게 되겠네요. 이제 소스를 수정해 보도록 하겠습니다.


앱 아웃라인

앱의 코드 아우트라인은 지난번과 달라진 것이 없습니다. 역할과 이번 수정으로 변경되는 사항을 소개하겠습니다.

1. main 함수에서는 runApp함수로 App위젯을 넣어 플러터를 기동 해주고 있습니다.

2. urls 변수는 사진을 url을 저장하는 리스트 변수입니다.

3. PhotoState 클래스는 사진의 상태를 나타내는 위젯이 아닌 단순 클래스입니다. 수정사항은 필터를 통해 사진이 표시되어야 하는지 말아야 하는지 판단하는 변수가 추가됩니다.

4. App 클래스는  stateful 위젯으로 AppState와 쌍으로 이루는 클래스입니다.

5. AppState 클래스는 State <App>을 상속받는 클래스로 stateful 위젯의 State클래스입니다. Drawer에 출력할 목록인 tags가 추가되었고, 서랍의 태그 목록을 클릭했을 때의 이벤트를 처리할 메서드가 추가됩니다. 또한 기존 toggleTagging 메서드가 수정됩니다.

6. Gallery는 stateless위젯으로 Scaffold를 리턴해주고 있습니다. 스캐폴드에 drawer를 추가하였습니다. GridView에서 사진 위젯을 리턴하기 전에 필터를 하는 기능을 추가하였습니다.

7. Photo클래스는 stateless위젯으로 사진을 포함하는 위젯을 리턴하고 있습니다.

 

지난 글의 소스에서 PhotoState클래스, AppState클래스, Gallery클래스에서 변경사항이 생겼습니다. 변경된 클래스를 하나씩 살펴보겠습니다.


PhotoState 클래스

PhotoState는 각 사진의 상태를 나타내는 클래스입니다. display는 부울로 사진이 갤러리에 출력 대상인지 아닌지를 판단하는 변수이며 초기값으로 true가 설정됩니다. tags는 사진에 부여되는 Set<String>타입의 변수이며 사진을 선택후 Drawer에서 태그 목록중 하나를 선택하면 이 tags변수에 태그를 저장하게됩니다. 초기값으로는 {}로 아무런 태그를 가지고 있지않는 상태입니다.

 

AppState 클래스

AppState 클래스에서는 Set<String>타입의 tags가 추가되었습니다. 이 tags변수를 사용해서 Drawer의 태그 목록을 표시하게 됩니다. 또한 onPhotoSelect메서드가 추가 되었습니다. 그 외로 사소히 변경된 부분과 함께 살펴보겠습니다.

 

AppState클래스, toggleTagging 메서드(수정)

이전에 toggleTagging 메소드는 사진을 길게 클릭했을 때 태그 모드로 상태를 바꿔주는 역할을 하는 메소드 였습니다. 이제는 url 매개변수를 건네받게 변경되었고 건네받은 url로 태그모드 여부를 확인한 후 길게 클릭한 대상의 사진의 선택 여부의 상태인 selected를 true로 설정하고 있습니다. 그리고 그 외의 사진은 전부다 false로 설정해 주고 있습니다. 이렇게 변경하므로 동작은 사진을 길게 클릭하면 태그 모드와 변환됨과 동시에 길게 클릭한 사진의 체크박스가 바로 선택 상태가 되고 그 외의 사진들은 전부다 해제 상태가 됩니다.

 

AppState클래스, selectTag 메소드(추가)

selectTag 메서드는 서랍에서 태그 목록 중 하나가 클릭되면 호출되는 메소드 입니다. setState안에 함수를 넣어 프레임워크에 상태가 갱신됨을 알려줍니다.

1. 건네주는 함수는 우선 if문으로 태그 모드인지 아닌지 판단하게 됩니다. isTaggingMod가 true 즉 태그 모드일 경우 선택한 태그가 all 아닌 경우에 한해서 photoStates를 루프로 돌며 선택된 사진을 찾아 해당 사진의 tags변수에 선택한 태그를 추가합니다. 그런 후 toggleTagging을 호출해 태그 모드에서 빠져나가게 해 줍니다.

2. 태그 모드가 아닐 경우 갤러리에 필터를 걸어주는 역할을 합니다. 사진의 상태 배열인 photoStates를 순회하며 각 사진의 display상태를 true나 false로 갱신해줍니다. 단 태그가 all일 경우 사진이 가지고 있는 태그에 상관없이 모두 true로 갱신해줍니다. 그 이외에는 contains로 태그가 포함되어있는지 확인하고 리턴되는 부울 값을 세팅해 줍니다.

 

AppState클래스, build 메서드(변경)

AppState의 build 메서드입니다. MaterialApp을 리턴해주고 있고 home에서 Gallery를 설정해주고 있습니다. 변경된 부분은 새로 추가된 상태 값인 tags와 Drawer에서 목록을 클릭했을 때 실행할 콜백 메서드를 하위 위젯에 건네주는 부분입니다.

 

Gallery 클래스

Gallery 위젯 역시 상태 값이 추가됨에 따라 tag와, select태그 프로퍼티가 추가되었고 생성자도 변경되었습니다. build메서드에서 제일 중요한 변경이 있었는데요.

 

Galelry클래스, build 메서드(변경)

build 메서드에서는 스캐폴드 위젯을 리턴해주고 있고, body에 GridView로 Photo위젯을 표시하며 갤러리를 만들어 주고 있습니다. GridView의 children에서 Photo 위젯의 리스트를 담고 있는데, 변경된 사항이 photoStates의 where메서드를 호출해주고 있다는 점입니다.

1. where를 통해 선택된 태그의 사진만 보여주는 필터 기능을 해주고 있습니다. where는 자바스크립트에서 filter와 같은 기능을 해줍니다. 즉 테스트에 통과하는 요소의 컬렉션을 반환해주는데요. 위 예에서는 ps.display가 판별식이 되므로 display속성이 true인 요소만 걸러져서 배열로 반환되게 됩니다. 언제 display가 true가 되었는지 기억하시나요? display가 true가 되는 시나리오는 처음 photoState가 초기화되었을 때와 서랍에서 All이 선택되었을 때, 서랍에서 특정 태그를 선택되었을때 해당 태그를 가지는 사진이 true가 됩니다. 이것으로 태그로 사진을 필터 하는 기능이 간단히 구현되었습니다.

2. drawer속성에 Drawer 위젯을 넣어주고 있습니다. child로는 ListView를 가지고 ListView에서는 tags를 map으로 순회하며 ListTile안에 Text위젯을 만들어 주고 있습니다. 그리고 ListTile을 클릭했을 때 콜백 되는 함수로 selectTag를 넣어주고 있습니다. 상위 위젯에서 건네받은 selectTag 함수는 두 가지 동작을 하게 됩니다. 태그 모드일 때는 사진에 태그 지정을, 태그 모드가 아닐 때는 해당하는 태그로 갤러리를 필터 해서 보이게 됩니다. 서랍의 목록이 한번 클릭하면 서랍이 화면에서 사라져야 하므로 Navigator.of(context). pop()을 호출하고 있습니다. 플러터의 내비게이션 Stack에 대해 자세히 알고 싶으시면 이쪽 글을 참고해주세요.


이제 코딩이 다 끝났습니다. 화면을 살펴보겠습니다.

사진에 태그를 설정하고, 태그로 화면 필터가 잘 작동합니다!!🥳


여기까지 수고하셨습니다. 위 예와 같은 소스는 stateful 위젯을 이해하기에는 좋은 연습이 되지만, 실제 업무에서 사용하기에는 부족한 코드입니다. 다음 포스트에서 코드를 개선해 가면서 상태를 효율적으로 공유하는 법에 대해 알아보도록 하겠습니다.

 

댓글