AnimatableなDrawable自作したときにハマったので。
Drawable
View
のonDraw()
にあたる処理だけを切り出した抽象クラスです。
View
の場合は主にonMeasure()
、onLayout()
、onDraw()
の3つを担いますが、Drawable
はonDraw()
のみになります。
サイズや配置などは、使う側(View)に委ねられています。
Drawable.invalidateSelf()
View.invalidate()
同様、再描画を促すメソッドです。invalidate()
のDrawable
版と思ってかまわないと思います。
とはいえ、Drawable
はView
と違い、描画しかサポートしていないため、本来再描画を促すことはできません。
ではinvalidateSelf()
はどのように再描画可能にしているのか?
これにはDrawable.setCalllback()
メソッドが関係しています。
Drawable.setCallback()
setCallback()
とはなんなのか?(名前雑すぎて役割が何もつかめないんだけど…)
setCallback()
の引数Drawable.Callback
インターフェースは以下のようになっています。
public interface Callback {
void invalidateDrawable(Drawable who);
void scheduleDrawable(Drawable who, Runnable what, long when);
void unscheduleDrawable(Drawable who, Runnable what);
}
Drawable.Callback
の役割は2つinvalidateDrawable()
とscheduleDrawable()
です。
invalidateDrawable()
はwho
(SelfにあたるDrawable)がView.invalidate()
を要求するコールバックです。
scheduleDrawable()
はwho
が特定の時刻にスケジューリングされたRunnable
の実行を要求するコールバックです。
このDrawable.Callback
ですが、基本的に実装する必要はありません。というのも、既にView
が実装してくれているからです。1
CustomView
などでinvalidateSelf()
を有効にする場合は、**drawable.setCallback(this)
**するだけで構いません。
ここまでで、invalidateSelf()
はDrawable.Callback
にinvalidate()
を要求するというメソッドであることがわかります。
invalidateSelf()
をするためには準備が必要なんですね。(ハマり)
View.verifyDrawable()
先ほど、View
はDrawable.Callback
を実装しているので、drawable.setCallback(this)
するだけでinvalidateSelf()
は動くと書きましたが、これだけでは動かないケースが存在します。
View
のinvalidateDrawable()
の実装では、invalidate()
を呼び出せるDrawable
を制限しています。
この条件を実装しているのがView.verifyDrawable()
です。
デフォルトでは以下のように実装されています。
@CallSuper
protected boolean verifyDrawable(@NonNull Drawable who) {
return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who);
}
background
及びforeground
に設定されているdrawable
以外のinvalidateDrawable()
は承認されません。
ImageView
の場合はこれに加えて、src
にあたるDrawable
を追加しています。
つまり場合によっては、setCallback(this)
をしてもverifyDrawable()
をoverrideし忘れるとinvalidate()
されないということです。
気をつけましょう。(2度目のハマり)
注釈
-
supportライブラリのように、
Drawable
のラッパーをつくる場合は自前で実装したりするようです ↩