独自のボタンを作るため、 ImageButton
の background
に AnimationDrawable
を指定することはよくあると思います。
「簡単な繰り返しアニメーションだから、WebページのGIFアニメみたく自動的に再生開始してくれたらいいのに!」
しかも
有効時と無効時では別のDrawableを表示する
( StateListDrawable
の中に AnimationDrawable
を入れる)
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!--無効時 (pngファイル1枚)-->
<item android:state_enabled="false" android:drawable="@drawable/button_disable" />
<!--有効時(AnimationDrawable)-->
<item android:drawable="@drawable/button_enable_animating" />
</selector>
なんてなったときにはどうしたらいいのでしょう。
結論
結論を先に。
ImageButton
を継承したクラスを作ってどうにかしました。
適当に background
や src
にリソースを突っ込むと再生してくれます。
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.ImageButton;
public class AnimationAutoStartImageButton extends ImageButton {
public AnimationAutoStartImageButton(Context context) {
super(context);
}
public AnimationAutoStartImageButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AnimationAutoStartImageButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
startAnimationOfDrawable(getDrawable());
startAnimationOfDrawable(getBackground());
}
private void startAnimationOfDrawable(@Nullable Drawable drawable) {
if (drawable == null) {
return;
}
Drawable surface = drawable.getCurrent();
if (!(surface instanceof AnimationDrawable)) {
return;
}
AnimationDrawable animDraw = (AnimationDrawable)surface;
if (!animDraw.isRunning()) {
animDraw.start();
}
}
}
結局、何が問題だったのか
いくつかあります。
-
background
に指定したAnimationDrawable
はAnimationDrawable#start()
を叩かないとアニメーションが再生されない -
AnimationDrawable
inStateListDrawable
とかやると単純にstart()
叩けない
background
に指定した AnimationDrawable
は AnimationDrawable#start()
を叩かないとアニメーションが再生されない
どうやら、 src
に指定した AnimationDrawable は自動的に再生されるらしいのです。
参考:Animation-list (animationDrawable) autostart
が、srcに指定してしまうと、ボタンの柄を変更する事ができません。backgroundを使うしかない。
そうなると、コードからbackgroundのAnimationDrawableを取得して start()
を叩くしかない…
なんて面倒なんだ!
AnimationDrawable
in StateListDrawable
とかやると単純に start()
叩けない
StateListDrawable#getCurrent()
で現在のDrawableを取得して、それに対して start()
を叩く、という面倒なことをしないといけません。
しかも、 getCurrent()
でとれるDrawableがAnimationDrawableである保証はどこにもない!
いちいちインスタンスの型の確認が必要!
つらい!
まとめ
AnimationDrawableに自動再生のオプションとかがあれば、こんなややこしいことしなくて済んだのになぁ、という無い物ねだりでした。