AndroidDay 24

Material Design度が高まるRipple Effect対応


概要

Material Design対応を行っているアプリが増えてきたと感じる今日この頃ですが、みなさんRipple Effectの対応は行っていますか。

Ripple EffectはMaterial Designの中でもキーになる表現効果ですが、APIレベル21(Lollipop)以上のOSでないと標準の仕組みでは扱えないため後回しにしているアプリも多いのではないかと思います。

今回は、私が開発に携わっている女性向けファッションアプリ iQON で、Ripple Effect対応を行った際の話を書きたいと思います。

iqon_anim.gif


対応方針

Ripple Effect対応を行う上で、まずは以下のような対応方針を定めました。


1. 標準の仕組みを使って対応させる

Ripple Effectはバックポートされたサードパーティ製のLibraryがいくつか存在しますが、今回はそのようなLibraryは使わないで、OSが標準で提供している仕組みを使って対応を行うことにしました。

そのため、実際にRipple Effectが現れているのはAPIレベル21以上のOSのみになります。ただし、APIレベル21未満の場合でもPressed時のタッチフィードバックをRipple Effectと同じ領域で表示されるようにします。

サードパーティ製のLibraryを使わない理由としては、Ripple Effectの部分をサードパーティ製のLibraryに依存してしまうとほぼすべての画面が依存することになってしまい、何かあった際の改修が困難になる可能性があると考えたからです。


2. できるだけdrawable-v21以下にファイルを作らない

長期的に運用を続けるアプリの場合、バージョン別に同名ファイルを作りすぎてしまうと改修に弱い仕組みになる可能性があるため、できるだけdrawable-v21以下にファイルを作らないようにしました。

ただしUIの表現上、rippleタグを使う必要がある場合や ?android:attr/selectableItemBackgroundBorderless を使う必要がある場合は致し方無いと判断しています。


3. ImageViewなどのパーツを設置しているViewGroupをタップ領域にする場合は、パーツをRipple Effectでオーバーレイさせる

アプリによっては、設置したパーツをオーバーレイするアプリ、しないアプリがありますが、今回はパーツを設置する場合にはオーバーレイするように統一することにしました。

理由としては、オーバーレイさせた方がRipple Effectの見栄えが良いためです。

オーバーレイしていない場合

background.gif

オーバーレイしている場合

foreground.gif


4. Ripple Effectの色は指定した色にする

この項目に関してはアプリ特有の問題になりますが、アプリ内でのデザイン統一のためにRipple Effectの色はデフォルトのグレー以外の指定した色になるようにしました。

APIレベル21未満のPressed時のタッチフィードバックも同じ色になるようにしました。


実装

上記の対応方針を踏まえて、実際にやったことを紹介していきます。


OnClickListenerを実装するViewのbackground/foregroundにはselectableItemBackgroundを設定

例外もありますが、OnClickListenerを実装するほとんどのViewのbackground/foregroundには ?android:attr/selectableItemBackground を設定しました。

?android:attr/selectableItemBackground を設定することで、そのViewにはPressed時にタッチフィードバックが表示されるようになります。

もちろんAPIレベル21以上ではRipple Effectが表示されるようになります。

他のDrawableを設定する場合には、Drawable内で ?android:attr/selectableItemBackground を設定するようにすれば対応可能です。


パーツをオーバーレイさせる場合にはforegroundにselectableItemBackgroundを設定

ImageViewなどのパーツをオーバーレイさせたい場合には、OnClickListenerを実装するViewGroupのforegroundに ?android:attr/selectableItemBackground を設定します。

ただし、foregroundのattributeを持つViewGroupは FrameLayout やFrameLayoutを継承した CardView などに限られるため注意が必要です。

場合によってはViewの階層が深くなってしまう場合もあると思いますが、どうしても気になる場合はGoogle I/Oアプリのコードである ForegroundLinearLayout.java などを参考にCustomViewを作ってしまえば回避できると思います。


Ripple Effectの色を変えるためにcolorControlHighlightに色を設定

?android:attr/selectableItemBackground を設定時のRipple Effect(APIレベル21以上)の色と colorControlHighlight の色は連動しているため、ベースで使用しているstyleに colorControlHighlight のitemを追加します。


styles.xml

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

<item name="colorControlHighlight">@color/color_control_highlight</item>
</style>


APIレベル21未満のPressed時のためにstyles.xmlをバージョン別に分ける

APIレベル21未満のPressed時のタッチフィードバックをRipple Effectと同じ色にするためにstyleに android:selectableItemBackground のitemを追加します。

ただし、これだとAPIレベル21以上も影響を受けてしまいRipple Effectが表示されなくなるので android:selectableItemBackground のitemを追加しない v21/styles.xml を作成してあげる必要があります(もっと良いやり方ないものか...)。


styles.xml

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

<item name="colorPrimary">@color/color_primary</item>
<item name="colorPrimaryDark">@color/color_primary_dark</item>
<item name="colorAccent">@color/color_accent</item>
<item name="colorControlHighlight">@color/color_control_highlight</item>
<item name="android:selectableItemBackground">@drawable/pre_lollipop_selectable_item</item>
</style>


pre_lollipop_selectable_item.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">

<item android:drawable="@color/color_control_highlight" android:state_pressed="true" />
<item android:drawable="@android:color/transparent" />
</selector>


v21/styles.xml

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

<item name="colorPrimary">@color/color_primary</item>
<item name="colorPrimaryDark">@color/color_primary_dark</item>
<item name="colorAccent">@color/color_accent</item>
<item name="colorControlHighlight">@color/color_control_highlight</item>
</style>


サンプルコード

今回の内容のサンプルコードはこちらになります。

https://github.com/nissiy/RippleSample

興味がある方は、APIレベル21以上と、APIレベル21未満の端末にビルドして見比べてみてください。


まとめ

APIレベル21以上でしか有効にならないですが ?android:attr/selectableItemBackground の使用に絞れば比較的楽にRipple Effect対応が行えます。

今回紹介した方法を用いれば、APIレベル21未満のPressed時のタッチフィードバックも一緒に最適化できるのでオススメです。

一気にMaterial Design度が高まるのでRipple Effect対応を行えていないアプリは対応を検討してみてはいかがでしょうか。