/ PROJECT, ANDROID, RECYCLERVIEW, FASTSCROLLER

Recyclerview Fastscroller 라이브러리

drawing
위 그림처럼 갤러리나 수많은 아이템을 보여줄 때, 순차적으로 스크롤하여 접근하는 대신 스크롤 바를 잡고 바로 이동하는 역활을 하는 것을 FastScroller라고 합니다. FastScroller를 한마디로 이야기하면 “드래그하여 특정한 위치로 이동가능한 스크롤 바”라고 정의 할 수 있습니다.

Recyclerview는 FastScroller를 가지고있고 RecyclerView를 xml로 정의할때 app:fastScrollEnabled="true" 한줄만 넣어주면 해당기능을 지원 할 것 처럼 생겼습니다. 역시 구글형!

public RecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    setScrollContainer(true);
    setFocusableInTouchMode(true);
    ...
    mEnableFastScroller = a.getBoolean(R.styleable.RecyclerView_fastScrollEnabled, false);
    ...
    if (mEnableFastScroller) {
         ... // 알아서 다 해줄 것 처럼 해두고...
         initFastScroller(verticalThumbDrawable, verticalTrackDrawable,
                 horizontalThumbDrawable, horizontalTrackDrawable);
    }

하지만 이 클래스는 그림의 떡 입니다.

FastScroller는 package private이며, adapter와 달리 사용자가 직접 접근하여 커스텀 할 수 없는 형태로 선언 되어있습니다. RecyclerView의 생성자에서 FastScroller 객체를 만들때 자기 자신을 생성자에 넘겨 버리는 것으로 완료되어 버립니다. 더 이상 RecyclerView 객체에서 접근 할 수 없는 구조입니다. (link)

void initFastScroller(StateListDrawable verticalThumbDrawable,
    ...
    Resources resources = getContext().getResources();
    // 왜죠? 구글형? 무책임하게 생성만 하고 끝이라니요.
    new FastScroller(this, verticalThumbDrawable, verticalTrackDrawable,
            horizontalThumbDrawable, horizontalTrackDrawable,
            resources.getDimensionPixelSize(R.dimen.fastscroll_default_thickness),
            resources.getDimensionPixelSize(R.dimen.fastscroll_minimum_range),
            resources.getDimensionPixelOffset(R.dimen.fastscroll_margin));
}

왜죠? 구글형?

이렇게 구글형이 만들어준 Fastscroller을 일단 한번 써보겠습니다. 구글형인데, 평타는 치겠죠! android:orientation="vertical으로 명시 했지만 initFastScroller메서드에서는 vertical,horizontal 각각의 thumb와 track를 정의하지 않으면 아래와 같은 익셉션을 발생시켜버립니다.

if (verticalThumbDrawable == null || verticalTrackDrawable == null
        || horizontalThumbDrawable == null || horizontalTrackDrawable == null) {
    throw new IllegalArgumentException(
            "Trying to set fast scroller without both required drawables."
                    + exceptionLabel());

그냥 VectorDrawable을 쓰면, StateListDrawable을 달라고 하시네요.

Caused by: java.lang.ClassCastException: android.graphics.drawable.VectorDrawable 
cannot be cast to android.graphics.drawable.StateListDrawable
   at androidx.recyclerview.widget.RecyclerView.<init>(RecyclerView.java:702)
   at androidx.recyclerview.widget.RecyclerView.<init>(RecyclerView.java:650)
   at java.lang.reflect.Constructor.newInstance0(Native Method) 
   at java.lang.reflect.Constructor.newInstance(Constructor.java:334) 

그래고 이까짓 xml이야 귀찮아도 머리는 쉬고 손가락만 움직이면 되니깐요. 괜찮아요. 구글형이 시키는대로 했습니다.

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    app:fastScrollEnabled="true"
    app:fastScrollHorizontalThumbDrawable="@drawable/thumb_selector"
    app:fastScrollHorizontalTrackDrawable="@drawable/track"
    app:fastScrollVerticalThumbDrawable="@drawable/thumb_selector"
    app:fastScrollVerticalTrackDrawable="@drawable/track_item"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

여기서 끝이났다면 이 포스팅이 작성 되지 않았겠죠. 사용자와 디자이너 그리고 기획자가 용납할 수 없는 문제가 여기서 발생합니다.

문제

아이템의 수가 적을때는 아쉬운 점이 있어도 그나마 사용하는데 문제는 없었습니다. 하지만, 아이템의 수가 늘어나면 스크롤이 길어지고 thumb의 높이는 0px로 수렴하게됩니다. 아쉽게도 일정크기를 유지 하도록 하는 옵션이 제공되지 않습니다. 아이템이 1000개만 넘어가도 이미 손가락으로 터치는 불가능할 정도로 작아집니다. 이 문제는 구글 이슈트레커에 등록된지 4년째 이지만 진행되는 내용은 없는 것 같습니다.(https://issuetracker.google.com/issues/64729576)

그외 단점들

터치할 수 없는 스크롤 바를 해결하기위해 고민하다가 문득 또 다른 해법이 떠올랐습니다. 고리짝 시절에 사용해 봤던 android.view.View의 scrollbarThumbVertical이라는 속성이 있습니다. RecyclerView도 View를 상속하니 무리없이 xml에 한줄로 적용이 가능했습니다. VectorDrawable로 정의도 가능하고, 스크롤의 길이에 따라 크기가 변하지도 않습니다.

하지만, 이게 문제가 없다면 굳이 RecyclerView 저런 속성들과 클래스들이 추가 되지 않았겠죠.

scrollbarThumbVertical속성으로 그려지게 되는 ScrollBarDrawable 객체의 콜백은 스크롤하는 범위의 모든 아이템이 OnBindViewHolder를 호출하게 됩니다. 수십 수백개 정도는 큰 문제가 되지않지만,구조에 따라 천단위를 넘어가기 시작하면 스크롤중 아이템의 이미지를 그리는 앱이나, 아이템의 모델이 큰 경우에는 상당한 부담이 될 것 입니다.

결론 : 그래서 recyclerview-fastscroller를 직접 구현 하게 되었습니다.

다음편에서는 직접 구현한 FastScroller를 살펴보겠습니다. 단순한만큼 버그는 적고 잘 동작합니다.

한번 써보세요~ 👍

link : https://github.com/mond-al/recyclerview-fastscroller

Search

Get more post