관리 메뉴

나만을 위한 블로그

[Android] 리사이클러뷰 클릭 이벤트 본문

Android

[Android] 리사이클러뷰 클릭 이벤트

참깨빵위에참깨빵_ 2019. 11. 7. 21:23
728x90
반응형

참고한 블로그 : https://thepassion.tistory.com/301

 

RecyclerView는 선택된 아이템의 선택상태나 선택된 아이템 리스트 관리등의 기능을 제공하지 않는다.

이 글에선 아이템이 선택됐을 때 배경색을 변경하거나 리사이클러뷰 외부에서 선택 or 해제 처리를 하는 법에 대해 정리한다.

 

 

1. 특정 아이템 클릭 시 배경색상 변경

 

 

먼저 생각해 볼 수 있는 건 아이템이 클릭됐을 때 onClick() 리스너에서 itemView의 배경색을 바꾸는 것이다.

뷰홀더가 보관하는 itemView에 onClick 리스너를 설정했으므로, onClick() 리스너에서 넘어오는 View는 ViewHolder.itemView 객체다.

따라서 아래와 같이 배경색을 변경해 줄 수 있다.

 

 

선택 해제 처리는 onClick 이벤트 발생 시 클릭된 아이템의 position(ViewHolder.getAdapterPosition())과 선택 상태를 지정해놓고 토글시키는 방식을 썼다.

position 별 선택 상태를 저장하는 구조는 SparseBooleanArray라는 걸 썼다고 한다.

 

SparseBooleanArray : 구글 검색 시 "다중 삭제" 라는 키워드가 나온다. 이것은 리스트뷰에서 다중 선택 시 선택한 position에 대한 정보를 보관하는 객체고 get()을 호출해 선택된 position의 값을 구한다. get()은 해당 position에 값이 존재하면 true를 반환한다.

기본적으로 int를 boolean에 매핑한다. 즉 int를 키값, boolean을 value값으로 하는 맵과 같다. 이 방법은 HashMap을 써서 정수를 boolean에 매핑하는 것보다 효율적인 방법이다.

 

※ 디벨로퍼의 SparseBooleanArray : 정수를 boolean으로 매핑한다. 일반적인 boolean 배열과 달리 색인에 공백이 있을 수 있다. 이 기능은 HashMap을 써서 정수를 boolean에 매핑하는 것보다 메모리 효율성이 뛰어나다. 즉, 키밸류가 자동 박스화되는 걸 막고, 각 매핑에 대해 데이터 구조가 추가 입력 개체에 의존하지 않는다.

이 컨테이너는 2진수 검색을 써서 키를 찾으며 배열 데이터 구조에 매핑을 유지한다. 이 구현은 많은 항목을 포함할 수 있는 데이터 구조에 적합하지 않다. 검색에는 2진 검색이 필요하며 추가/제거에는 배열에 항목을 삽입 or 삭제해야 하므로, 일반적으론 기존 HashMap보다 느리다. 수백 개의 아이템들을 holding하고 있는 컨테이너는 성능 차이가 50% 미만으로 특별히 차이나진 않는다.

키(int)와 밸류(int)를 써서 이 컨테이너의 아이템 위로 반복(iterate)할 수 있다. 키(int)를 써서 인덱스의 오름차순으로 키를 반복하면 키가 오름차순으로 반환되거나 밸류(int)의 경우 키에 해당하는 밸류가 오름차순으로 반환된다.

 

 

리사이클러뷰 어댑터는 전체 아이템 개수에 기반해 적정수(한 화면에 표시되는 아이템 수 + 스크롤 시 사용할 여분의 아이템 개수)의 뷰홀더(View)를 미리 생성하고, 화면 상 표시되지 않는 뷰를 재사용하는 구조다.

클릭할 때의 뷰가 계속 같은 데이터를 표시한다고 보장할 수 없는 것이다. 즉, 아이템의 선택 상태는 position 기반으로 관리하되, 실제 선택 상태를 표시하는 건 뷰홀더에 데이터가 반영되는 시점에 처리해주면 될 것 같다.

뷰홀더의 getAdapterPosition()은 뷰홀더 재사용 여부와 상관없이 아이템 배치순서 상의 position(제로 베이스)을 리턴한다. DataSet 내의 인덱스 값이라고 생각해도 된다.

 

그러면

1. 아이템 클릭 시 선택 상태 저장 및 선택 상태 표시

2. 아이템 바인딩 시 선택 상태 표시

순서의 방법으로 구현해보면 될 것 같다.

 

(중략)

 

아이템 선택 상태가 변경되는 시점(아이템 클릭 이벤트 발생 or 아이템 선택/해제 메서드가 호출됐을 때)에 선택 상태를 저장(갱신)하고 데이터가 뷰에 바인딩되는 시점인 onBindViewHolder()에서 배경색을 바꾸도록 처리하면 될 것 같다.

 

다만 onBindViewHolder()가 호출되는 시점은 뷰에 데이터를 바인드해야 하는 상황이므로, 어댑터에게 데이터를 재바인딩해야 함을 알려줘야 한다. 코드 상으로는 setData() 메서드의 notifyDataSetChanged()가 그러하다.

리사이클러뷰 어댑터는 표시되는 데이터를 리바인딩해야 하는 상황에서 어댑터에게 이를 알려줄 수 있도록 notify~ 종류의 메서드를 제공한다. 데이터가 변경된 건 아니지만 강제로 데이터를 다시 그리도록 처리하는 일종의 트릭이다.

 

백그라운드의 색을 바꾸는 부분은 xml을 통해 처리할 수 있다. xml selector에 select된 상태, select되지 않은 상태에 적용할 색 or 이미지를 지정하고 대상 위젯의 백그라운드 속성으로 해당 selector를 할당하는 방식이다.

여기선 drawable 폴더 밑에 선택 상태에 따라 표시할 색을 지정하는 item_selector.xml을 작성했다.

또한 배경색으로 쓸 색상은 color.xml에 미리 지정해놔야 한다. 그 후 아이템을 표시할 레이아웃의 루트(최상위) 레이아웃에 백그라운드 속성(android:background)을 위 파일로 @drawable/item_selector로 지정해주면 된다.

그리고 onBindViewHolder()에서 코드를 아래처럼 수정하면 선택 상태에 따라 자동으로 배경색이 바뀐다.

 

 

롱클릭 이후 데이터를 선택하게 하거나 단일 선택 등 처리는 여기서 좀 응용하면 가능할 것 같다고 한다.

반응형
Comments