[Android] 상하 스크롤 중 내부 RecyclerView의 좌우 스크롤 유지

1. 상황

현재 한 Activity가 상하 스크롤이 되는 RecyclerView로 구성되어 있고, 그 아이템 중 하나가 좌우 스크롤 RecyclerView를 가지고 있다.

Activity 구성

RecyclerView는 View를 재사용하기 때문에 item1, item2, …의 뷰를 그릴 때 item1에서 사용한 뷰를 n번째 item에서 재사용할 수 있다. 따라서 다시 item1을 그릴 때 View를 초기화하게 되므로 item 내의 RecyclerView 스크롤이 초기화된다.

즉, item1의 좌우 스크롤을 움직인 후 아래로 스크롤링하고 item1 위치로 다시 돌아왔을 때 그 좌우 스크롤이 처음으로 되돌아가있는 이슈가 발견되었다.

2. 해결

1
2
3
4
val pos = (rv.layoutManager as LinearLayoutManager?)?.findFirstCompletelyVisibleItemPosition() ?: -1
if (pos != -1 && scrollInfo?.scrollPos != pos) {
scrollInfo?.scrollPos = pos
}

이렇게 하면 일단 현재 보고있는 item의 position을 얻어와 저장할 수 있다. 이 동작을 사용하여 아래와 같이 OnScrollListener에서 scrollPos와 scrollOffset을 저장한다.

scrollOffset은 scrollPos만으로는 해당 item의 맨 앞부분으로 스크롤이 움직이기 때문에 이를 현재 스크롤하던 위치로 옮겨주기 위함이다.

1
2
3
4
5
6
7
8
9
10
rv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val pos = (rv.layoutManager as LinearLayoutManager?)?.findFirstCompletelyVisibleItemPosition() ?: -1
if (pos != -1 && scrollInfo?.scrollPos != pos) {
scrollInfo?.scrollPos = pos
}
scrollInfo?.scrollOffset = rv.computeHorizontalScrollOffset()
}
})

그리고 저장한 scrollOffset을 사용하여 스크롤을 유지할 수 있는 함수는 아래와 같이 구성하였다.

1
2
3
4
5
6
7
8
9
10
private fun keepScroll(scrollInfo: ScrollInfo) {
var offset = 0
if (scrollInfo.scrollPos < goodsList.size - 2) {
offset = scrollInfo.scrollOffset
while (offset > itemWidth) {
offset -= itemWidth
}
}
(rv.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(scrollInfo.scrollPos, offset)
}

3. 번외

scrollToPositionWithOffset이 position과 offset 값을 받는 걸 이용하여, position은 0으로 고정하고 offset을 rv.computeHorizontalScrollOffset()을 저장한 값으로 넘겨주면 될 거라고 생각했으나 기대한대로 동작하지 않았다.

1
(rv.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(0, offset)

[Android] 상하 스크롤 중 내부 RecyclerView의 좌우 스크롤 유지

https://dl137584.github.io/2022/04/20/022-keep-horizontal-scroll-when-scrolling-vertically-other-recyclerview/

Author

LEEJS

Posted on

2022-04-20

Updated on

2022-04-20

Licensed under

댓글