Android
RecyclerView

RecyclerViewでFastScroll

ListViewやGridView(つまりAbsListView)なら、レイアウトXMLで以下のように書くだけで実現できた。

<ListView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:fastScrollEnabled="true" />

RecyclerViewではこれができない、という状況が長く続いていた。
ライブラリを導入しようにも、決定版になるようなものは出ていなかった(個人の感想)。

……と思っていたのだが、久しぶりに調べてみたところ、Support Library 26でAPIが追加されたとのこと。
https://developer.android.com/topic/libraries/support-library/revisions.html#26-0-0

New fastScrollEnabled boolean flag for RecyclerView. If enabled, fastScrollHorizontalThumbDrawable, fastScrollHorizontalTrackDrawable, fastScrollVerticalThumbDrawable, and fastScrollVerticalTrackDrawable must be set.

動作イメージ

サンプルコードの実装抜粋

https://gist.github.com/75py/3b510a511d3d3231bc409e5517207818

設定方法

Layout XML

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:fastScrollEnabled="true"
    app:fastScrollHorizontalThumbDrawable="@drawable/fast_scroll_thumb"
    app:fastScrollHorizontalTrackDrawable="@drawable/fast_scroll_track"
    app:fastScrollVerticalThumbDrawable="@drawable/fast_scroll_thumb"
    app:fastScrollVerticalTrackDrawable="@drawable/fast_scroll_track" />
  • android:fastScrollAlwaysVisibleのような細かい指定はできないので、AbsListViewと完全に同等のことができる、というわけではなさそう。
  • 縦横どちらかにしかスクロールしない場合でも、Vertical/Horizontal両方の指定が必要(いずれかが欠けていると例外がスローされる)

java.lang.IllegalArgumentException: Trying to set fast scroller without both required drawables.

Drawable XML

基本的には、これだけで良い。

fast_scroll_thumb.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape android:shape="rectangle">
            <solid android:color="#f00" />
        </shape>
    </item>
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#00f" />
        </shape>
    </item>
</selector>
fast_scroll_track.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#0f0" />
</shape>

個人的には、trackの方は透明でいいと思う。

fast_scroll_track_transparent.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@android:color/transparent" />
</shape>

Drawable XML(改善案 API23以降)

↑だと触れる範囲が非常に小さいので、正直言って使いづらい。

ソースを覗く限り、そのうち margin みたいな値が指定できるようになりそうだが、とりあえず Drawable を工夫してあげると、触れる範囲を広げることができる。

以下の例では、ツマミ8dpの左側40dpも触れるようにしてみた。
【2018/1/24追記】以下の例だと、API22以下でツマミの幅が48dpになってしまう。(自分のアプリはminSdkVersion=24にしているから気付かなかった)

fast_scroll_thumb2.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <layer-list>
            <item android:gravity="end">
                <shape android:shape="rectangle">
                    <solid android:color="#f00" />
                    <size android:width="8dp" />
                </shape>
            </item>
            <item>
                <shape android:shape="rectangle">
                    <solid android:color="@android:color/transparent" />
                    <size android:width="48dp" />
                </shape>
            </item>
        </layer-list>
    </item>
    <item>
        <layer-list>
            <item android:gravity="end">
                <shape android:shape="rectangle">
                    <solid android:color="#00f" />
                    <size android:width="8dp" />
                </shape>
            </item>
            <item>
                <shape android:shape="rectangle">
                    <solid android:color="@android:color/transparent" />
                    <size android:width="48dp" />
                </shape>
            </item>
        </layer-list>
    </item>
</selector>

Drawable XML(改善案その2)

 前述の例だと、API22以下でツマミの幅が48dpになってしまう。
(API22-23の間にXMLの解釈方法が変わっているようだが、どういう理屈かまでは追っていない)
変更点は「gravity → left」のみ。。

fast_scroll_thumb3.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <layer-list>
            <item android:left="40dp">
                <shape android:shape="rectangle">
                    <solid android:color="#f00" />
                    <size android:width="8dp" />
                </shape>
            </item>
            <item>
                <shape android:shape="rectangle">
                    <solid android:color="@android:color/transparent" />
                    <size android:width="48dp" />
                </shape>
            </item>
        </layer-list>
    </item>
    <item>
        <layer-list>
            <item android:left="40dp">
                <shape android:shape="rectangle">
                    <solid android:color="#00f" />
                    <size android:width="8dp" />
                </shape>
            </item>
            <item>
                <shape android:shape="rectangle">
                    <solid android:color="@android:color/transparent" />
                    <size android:width="48dp" />
                </shape>
            </item>
        </layer-list>
    </item>
</selector>