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
<?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
基本的には、これだけで良い。
<?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>
<?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の方は透明でいいと思う。
<?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にしているから気付かなかった)
<?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」のみ。。
<?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>