viewpager를 recyclerview안에서 사용하기
recyclerview는 너무도 당연히 많이 쓰고 있는 뷰입니다.
거의 모든 리스트를 표현하는데 쓰이죠.
마찬가지로 viewpager도 많이 쓰이는 뷰입니다.
좌우로 스와이프하여 컨텐츠를 볼수 있는 형태의 뷰이며,
여러장의 사진 또는 콘텐츠를 스와이프하여 본다던지 하는 경우에 많이 쓰이고,
여러개의 배너화면을 보여주기 위해서도 많이 쓰이지요.
recyclerview안에 viewpager를 넣게 되는 일도 비일비재 합니다.
recyclerview를 사용하여 리스트를 보여주되 첫번째 row에는 현재 진행중인 이벤트를 보여준다거나 하는 등의 뷰가 가장 흔하죠.
구글플레이에서 뒤적이다가 찾은 앱중에 하나의 스크린샷입니다.
이런 용도로 활용되는 경우가 많습니다.
우리도 한번 구현해볼까요?
시연 영상보시죠.
각각의 row마다 viewpager를 넣었습니다.
물론 특정 row에만 넣을수도있죠.
보통 이러한 기능을 구현할때
그냥 recyclerview 만들고 viewholder만들고 그안에 viewpager넣으면 끝 아닌가?
이렇게 생각하실겁니다. 물론 맞습니다.
그런데 어쩌면 미처 생각하지 못했던 다른동작을 하나 발견하게되는데요.
당연히 이 글을 보고 계시는 안드로이드 개발자분들이라면 알고 계시겠지만
안드로이드의 recyclerview의 경우는 보이지 않는 row는 사라졌다가 나중에 다른 row가 보여질때 재활용하는데에 쓰입니다.
그렇기 때문에 내가 3페이지까지 보았던 viewpager가 있는 row가 다른 리스트를 보느라고 사라졌다가 다시 나타나는경우
recyclerview가 재활용되었기 때문에
내가 보고있던 page를 가리키지 않는다는것인데요.
바로 이 문제를 해결하기 위해서는 약간의 꼼수가 필요합니다.
(샘플소스코드에서도 확인하실수 있습니다.)
핵심 포인트만 말씀드리자면
@Override
public void onViewRecycled(ViewHolder holder) {
mViewPagerState.put(holder.getAdapterPosition(), holder.vp.getCurrentItem());
super.onViewRecycled(holder);
}
recyclerview adapter는 row가 재활용이 되기 위해 내부데이터를 지우기 바로 전에
onViewRecycled를 호출하는데요
이때 해당 viewholder가 가지고 있는 viewpager의 현재 위치를 기억해 둔다음에,
다시 해당 row가 불러와질때 저장되어있던 위치로 viewpager를 다시 설정하는 방식입니다.
소스코드를 보시면 별개의 hashmap에 row의 position을 key로 하여 각 row의 viewpager가 가리키고 있는 현재 페이지를
저장해두었습니다.
그리고 row를 불러올때 저장해두고 있던 페이지값이 있으면 그 페이지로 다시 설정을 해주는 방식입니다.
원래는 여기까지가 포스팅의 끝입니다만, one more thing.
각각의 row마다 viewpager를 넣을때는 반드시 알아야할 사항이 1개 있습니다.
하나의 recyclerview에서 여러개의 viewpager를 사용하면
맨 첫번째의 viewpager만 동작하고 나머지 것들은 동작을 하지 않는다는 것을 발견하게 되는데,
저도 구글링을 통해 알아보니깐
viewpager는 init될때 내부적으로 id를 할당하는것이 없어서 그렇다고 하네요.
그래서
viewHolder.vp.setId(position+1);
이렇게 viewpager에 setId 를 통해서 임의의 유니크한갑들을 저마다 설정해주시면 됩니다.
샘플소스코드는 여기에 있습니다. 많은 도움이 되길 바랍니다.
https://github.com/spotlight21c/viewpagerinrecyclerview