SeekBarをカスタマイズする


UIパーツは基本的にシステムデフォルトのものをそのまま使ったほうがよい主義者なのですが、ちょっとした変更はしたくなることがあり、SeekBarのカスタマイズってどうやるんだけっけ、をまとめてみます。

Androidのデフォルトのシークバーは、(プロジェクトのテンプレートから作成した場合のTheme.MaterialComponents系テーマを使ったものの場合、以下このテーマを前提にしています)
以下のような見た目をしています。

テーマカラーの変更

単に色を変更するなら、colorSecondaryで指定した色が使われるためこれで変更できます。

<style name="Theme.MyApplication" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
    <item name="colorSecondary">@color/purple_500</item>

バーが伸びる前のところの色は、Theme.MaterialComponentsなら、colorControlNormalの色と、android:disabledAlphaのα値を掛け合わせたものになっており、これで変更可能です。

<style name="Theme.MyApplication" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
    <item name="colorControlNormal">@color/purple_500</item>
    <item name="android:disabledAlpha">1.0</item>

つまみの形状変更

移動させるところのつまみ部分はレイアウトXMLにてandroid:thumbでDrawableを指定することで変更可能です。

<SeekBar
    android:thumb="@mipmap/ic_launcher"

バーの形状変更

バーの形状変更はちょっと面倒です。DrawableをレイアウトXMLにてandroid:progressDrawableでDrawableを指定することで変更可能です。

<SeekBar
    android:progressDrawable="@drawable/progress"

ここで指定するDrawableは特定のIDを持つlayer-listである必要があります。
ベースの部分が@android:id/background、プログレスの部分が@android:id/progressです。
secondaryProgressが必要な場合は@android:id/secondaryProgressを使いますが、これは今回扱いません。

まずは単純に色を指定します。progressについては、この色で上書きするため<clip>で囲んで指定します。

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background">
        <color android:color="#000" />
    </item>

    <item android:id="@android:id/progress">
        <clip>
            <color android:color="#f00" />
        </clip>
    </item>
</layer-list>

すると以下のようになります。
ちょっと思ってたのと違いますよねー

ちなみに、この大きさはドラッグ中のthumbの大きさと同じになっているみたいですが、thumbを他のDrawableにしたり、SeekBarにpaddingを設定しても変わらないようです

形状を角丸にしてみます。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background">
        <shape android:shape="rectangle">
            <corners android:radius="16dp"/>
            <solid android:color="#000"/>
        </shape>
    </item>

    <item android:id="@android:id/progress">
        <clip>
            <shape android:shape="rectangle">
                <corners android:radius="16dp"/>
                <solid android:color="#f00"/>
            </shape>
        </clip>
    </item>
</layer-list>

角丸にはなりましたね。うーん、でも太い

XMLだけでなんとかする場合、layer-listのitemにはtop/bottomのマージンを設定できますね。

<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@android:id/background"
        android:bottom="8dp"
        android:top="8dp"
        >
        <shape android:shape="rectangle">
            <corners android:radius="8dp" />
            <solid android:color="#000" />
        </shape>
    </item>

    <item
        android:id="@android:id/progress"
        android:bottom="8dp"
        android:top="8dp"
        >
        <clip>
            <shape android:shape="rectangle">
                <corners android:radius="8dp" />
                <solid android:color="#F00" />
            </shape>
        </clip>
    </item>
</layer-list>

ってことでわずかに角丸になったSeekBarを作ることができます。

ただし、paddingで合わせるのは本来の方法ではないと思います。高さが変わったときなどに都度paddingの調整が必要になっていまいます。ですので、9-patchを使うほうが良いと思います。

9-patchを使ったバーのカスタマイズ

9-patchならさらに複雑な形状にもできますね。左右にぽっちがあるプログレスバーみたいなのを作りたいとします。

この場合、以下の2つの9-patch画像を作ります。

これをlayer-listから指定します。

<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background">
        <selector>
            <item android:drawable="@drawable/seek_background"/>
        </selector>
    </item>

    <item android:id="@android:id/progress">
        <clip>
            <selector>
                <item android:drawable="@drawable/seek_progress"/>
            </selector>
        </clip>
    </item>
</layer-list>

以上です。