2015年3月19日木曜日

【Android:Material対応】本来押さないViewを押した時でも色が変わる視覚効果を実装

Android開発で、時に、ImageViewやTextViewなどの、押すことを考えられていない部品1に、押した時の処理を記述する(setOnClickListenerする)事があるかと思われます。

しかし、そのような時、Buttonなどと違って、押したことがユーザーにフィードバックされないため、押した時の視覚的な反応を自分で実装する必要があります。

ところで、Android Lollipop(5.0)からのMaterialテーマではボタンなどを押したときに波紋が広がるようになりましたね。とってもカッコいいです。
これをRippleというらしいです。

せっかくなら、Android5.0未満、つまりAPIレベル21未満では普通に、
それ以上ではRippleエフェクトがかかるように実装したい。

私がそこでハマったので、その方法を記録しておきます。

ちなみに何をするのかというと、効果をつけたいViewの上にImageViewを置き、そのImageViewのsrcとして波紋のDrawableを設定します。
Javaは一切書きません。

1: Widget、View、ViewGroup、Layoutなどの名称の関係が良く分からないのでまとめて部品と呼ぶことにします




■ファイル構造

プロジェクトのresフォルダの下にdrawableとdrawable-v21フォルダを作成、drawableとdrawable-v21に同名のxmlファイル、drawableにそれとは異なるファイル名のxmlファイルを作成します。
今回は下記のように、ripple_white.xmlを置きます。colors.xmlも、無い場合は置きます。

res
┣drawable
┃└ripple_white.xml
┣drawable-v21
┃└ripple_white.xml
┗values
  └colors.xml

■中身

まずはLollipop未満、APIレベル21未満のときの実装です。

colors.xmlに、色 item_pressed_white と item_focused_white を記述してください。
これは省略します。

drawable/ripple_white.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">

<item android:state_window_focused="false" android:drawable="@android:color/transparent" />

<item android:state_focused="true"  android:state_pressed="true" android:drawable="@color/item_pressed_white" />
<item android:state_focused="false" android:state_pressed="true" android:drawable="@color/item_pressed_white" />
<item android:state_focused="true"                                                  android:drawable="@color/item_focused_white" />
<item android:drawable="@android:color/transparent" />

</selector>

※コードハイライターの不具合かBloggerの仕様か、コード内にURLがあると表示がおかしくなるので、
http://という感じでスラッシュ部分を全角にしています。ご了承ください。 

selectorを使用しています。アニメーションをつけることでちょっとリッチな動きを目指します。
実はコレ、?android:attr/selectableItemBackgroundの中身をコピペして作ったものです。

今回Viewは常にEnabledだとして書いています。無効にしたい方は@color/item_disabled_whiteも作ったうえで、<item android:drawable="@color/item_disabled_white" android:state_enabled="false" />を追加するといいと思います。

drawable-v21/ripple_white.xml

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/item_pressed_white">

    <item android:id="@android:id/mask" android:drawable="@android:color/white" />

</ripple>
フォーカス時の色については実装することができませんでした。
5行目のandroid:drawableについては、色は関係なく、波紋が及ぶ範囲を指定するためのものの様です。
押した時の効果をつけたい部品が長方形ではない場合はここにその部品の形と同じ形のdrawableを指定すると良いです。

■適用する

あとはこれを適用するだけです。 FrameLayoutの中に押した時の効果をつけたい部品とImageViewを置き二つが完全に重なるように配置します。

ImageViewを上に配置し、ImageViewのソースとしてさっきのdrawable/ripple_whiteを指定します。
これで疑似的に、下の部品を押したフィードバックとして部品が白くなったように見せかけることができます。

なお、OnClickイベントは下の部品には届かないので、上のImageViewにsetOnClickListenerをします。

-----------------------------

以上で、疑似的ではありますがタッチした時の効果をつけることが出来ました。
最後にこれが動く様子を撮影した動画を貼って終わりにします。
質問やアドバイスがあったら気軽にコメントどうぞ。
それでは!



0 件のコメント:

コメントを投稿

Amazon