Android 5.0 が出てしまいましたね…
ApiLevelが21になって本当に良かった… Lのままだったらどうしようって不安だったのは他にもいたはずw
適当にAndroidアプリ作っていると、まあListViewからは逃げられません。
そしてそんなこんなで EnhancedListViewもDeprecatedに…
というわけで試しにRecyclerViewを触ってみました。
今回落ちは最後に書いてますので、お急ぎの方は一番最後からお読みください
とりあえず動かすだけ
動かすだけなら
-
RecyclerView.Adapter
を継承したAdapter作る - RecyclerViewにそのAdapterをセットする
- あとLayoutManagerなるものもセットする
だけで使えます
今まで暗黙的に(?)ViewHolderを作っていたと思いますが、
なんか強制されるようになったぐらいなイメージです
ググればすぐ出てくるんでこの辺は割愛
ただ使うだけなら楽です
個々の要素にアニメーションをかける
RecyclerView#setItemAnimator
で RecyclerView.ItemAnimator
を継承したクラスを突っ込むと
- 要素の追加
- 要素の削除
- 要素の移動
- 要素の変更
の時にアニメーションをかけることが可能です
ItemAnimatorを実装してみ…
なんと たった8個のメソッドを実装するだけ で良いのです
…
しかもちょっとしたことを気にしておけばOK!?
アニメーション開始時とか終了時とかに特定のメソッドを呼ぶ必要がちょっとあるだけ!
…
実装すべきメソッド紹介
- runPendingAnimations
- animateRemove ※1
- animateAdd ※1
- animateMove ※1
- animateChang ※1
- endAnimation
- endAnimations
- isRunning
まあ extends RecyclerView.ItemAnimator
とかやればIDEが勝手にひな形作ってくれますね
超ざっくりとした流れ
- RecyclerViewにItemAnimatorをセットする
- changeアニメーションを扱う場合は
ItemAnimator#setSupportsChangeAnimations(true)
を忘れずに
- Adapterでそれぞれのイベントにあった通知を呼ぶ
- notifyItemInserted
- notifyItemRangeInserted
- notifyItemRemoved
- notifyItemRangeRemoved
- notifyItemMoved
- notifyItemChanged
- notifyItemRagenChanged
- animate…(※1のやつら) にイベントが降ってくる
- 適当に保存しましょう
- true返しましょう
- アニメーション開始状態はここで作っておきましょう
- runPendingAnimationsが呼ばれる
- 3で保存したイベントを消化しましょう
- 3でtrueを返した数だけイベントが発生する 「わけではない」 ので、保存したイベントは すべて消化 しときましょう
- Add/Remove/Move/Change それぞれのアニメーション開始終了時に、それぞれ適したメソッド呼びましょう
- endAnimationsが呼ばれる
- なんかあったら呼ばれるからアニメーションキャンセルとか実装しておけよ!
です
だるっ
animate... 系のメソッドに関して
注意点は
- 対象ViewのAnimation開始状態はここで決めておくこと
だと思います
例えばAddでフェードインしたければ、引数として飛んでくるViewHolder
のitemView
(直接参照なのがまたすごいな…)のAlphaを0にするとか
ぶっちゃけ詳しく調べてないんですけど、メソッド内で全部Animation処理してfalse返すってのでも行けるかもしれませんが…
まーたぶんやめたほうが良いと思います、試してないけど。
それでいいならrunPendingAnimationsいらな…
runPendingAnimations
実際にAnimationをやる場所です
この時どういう順でAnimation処理するかも考えておきましょう
だって削除したら消えた部分は下のやつがせり上がってきたりするでしょ?
ってことは削除より前に移動アニメーション実行すると…
まあ見せ方考える必要ありますね
また注意点としてアニメーション開始時にアニメーションのタイプ(追加とか削除とか)に合わせて
- dispatchAddStarting
- dispatchRemoveStarting
- dispatchMoveStarting
- dispatchChangeStarting
を呼び、終了時もタイプに合わせて
- dispatchAddFinished
- dispatchRemoveFinished
- dispatchMoveFinished
- dispatchChangeFinished
を呼びましょう
更に、すべてのアニメーションが終了した時に
- dispatchAnimationsFinished
を呼ぶのを忘れ…
あとはendAnimet…
あ、もう説明するのだるい、コード読んで
そもそものDefaultのAnimationはDefaultItemAnimator
という形で存在します
$ANDROID_HOME/extras/android/m2repository/com/android/support/recyclerview-v7/21.0.0/recyclerview-v7-21.0.0-sources.jar
の中にあるんで。
RecyclerViewは8000行以上ありますけど、これは800行くらいだから…
だから…
辛い
そもそもさ、Animationのことだけ実装して渡せば、
**後のことはよしなにやってくれる!**とかがいいなぁ…
と思うんですよ?
超複雑なことやるならともかく…
これなら辛くない!(主に俺が)
なので実装しました
こちらの製品ではなんとあなたはAnimationのことだけ考えればOKです
recyclerView.setItemAnimator( SimpleItemAnimator.builder().
preAddAnimationState(v -> {
ViewCompat.setAlpha(v, 0);
return Unit.unit();
}).
addAnimation(animator -> animator.alpha(1)).
addDuration(500).
removeAnimation(animator ->
animator.translationXBy(recyclerView.getWidth())).
preChangeAnimationState((oldV, newVOpt, param) -> {
ViewCompat.setAlpha(oldV, 1);
newVOpt.foreach(newV -> {
ViewCompat.setAlpha(newV, 0);
ViewCompat.setRotationX(newV, -180);
return Unit.unit();
});
return Unit.unit();
}).
changeAnimation(
(forOld, param) -> forOld.rotationX(180).alpha(0),
(forNew, param) -> forNew.rotationX(0).alpha(1)).
isChangeAnimationMix(false).
changeDuration(500).
build());
なんとたったこれだけで
- 追加時は500msでフェードイン
- 削除時はdefault設定(120ms)で画面右に吹っ飛んで消える
- 変更時は古いViewが500msかけて回転して消えた後に、新しいViewが500msかけて回転して現れる
という設定が可能です!
動いているサンプル全容を知りたい場合はこちらのsampleをそのままBuildしてみてください
なお、何も設定しなくてもDefaultItemAnimatorと同様の動きをするはずです
そのへんはこの辺を…
ぇ?
RxAndroidとかFunctionalJavaついてきて困る?
しかもRetrolambda??
大丈夫、sampleにproguardの設定つけといたから(震え声
ぇ?
テスト無い?
いやだってUI周りでAndroid依存しまくりでもうめんど…
うん、まあ…
どう見ても完全に俺得ライブラリです、本当にありがとうございました
これらの依存関係の無い素敵なライブラリ誰か作ってください
もしくは次のupdateとかでそんな感じになってないかなぁ…