環境
- realm :
io.realm:realm-gradle-plugin:2.2.0
- kotlin :
org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.6
はじめに
Androidほぼ初心者です。のでお手柔らかに..
Recycler
を Recycle
と書いてしまうのがなかなか抜けない..
なにをしたか
RealmとRecyclerViewを使っているときに、 データの削除(モデル的には更新)をしたときにRowのAnimationを走らせたかったんですが色々あってやらなかったっていう話です。
はじめに?
AndroidでRecyclerViewのRowに対して 追加
, 更新
, 移動
, 削除
のアニメーションをするためには以下の方法が正攻法なのかなと感じました。
-
android.support.v7.widget.RecyclerView.ItemAnimator
を継承したサブクラスを作る - 必要なメソッドをoverrideする
- やりたい操作に対応して、Adapterの
notifyDataSetChanged
以外 の通知メソッドを呼び出す(※1) - ItemAnimatorのサブクラスにイベントが降ってくる。
※1: RecyclerViewのデータ操作通知メソッド
notifyItemChanged / notifyItemRangeChanged
notifyItemInserted / notifyItemRangeInserted
notifyItemMoved
notifyItemRemoved / notifyItemRangeRemoved
ItemAnimatorのサブクラス
今回は SimpleItemAnimatorを採用することにしました。
A wrapper class for ItemAnimator that records View bounds and decides whether it should run move, change, add or remove animations. This class also replicates the original ItemAnimator API.
公式Documentにもあるように ItemAnimatorを使いやすくwrapしてくれたクラスらしいので凝ったことをしないのであればこれで十分だと思ったからです。
次に必要なメソッド群を実装しました。
class MainTimelineRowAnimator : SimpleItemAnimator() {
override fun runPendingAnimations() {...}
override fun animateAdd(holder: RecyclerView.ViewHolder?): Boolean {...}
override fun animateChange(oldHolder: RecyclerView.ViewHolder?, newHolder: RecyclerView.ViewHolder?, fromLeft: Int, fromTop: Int, toLeft: Int, toTop: Int): Boolean {...}
override fun animateMove(holder: RecyclerView.ViewHolder?, fromX: Int, fromY: Int, toX: Int, toY: Int): Boolean {...}
override fun animateRemove(holder: RecyclerView.ViewHolder?): Boolean {...}
override fun isRunning(): Boolean {...}
override fun endAnimation(item: RecyclerView.ViewHolder?) {...}
override fun endAnimations() {...}
}
RecyclerViewのItemAnimatorの解説は この記事が非常にわかりやすかったです。
ここまでのまとめ
RecyclerViewでRowのAnimationをしたければ、 データセットの削除をした後に notifyItemXXX
系のメソッドを呼んであげればよさそうです。
ここでrealm
realmをRecyclerViewで使うには RealmRecyclerViewAdapter
を使っています。 では、ここの実装を見てみることにしましょう。
// Right now don't use generics, since we need maintain two different
// types of listeners until RealmList is properly supported.
// See https://github.com/realm/realm-java/issues/989
this.listener = hasAutoUpdates ? new RealmChangeListener() {
@Override
public void onChange(Object results) {
notifyDataSetChanged();
}
} : null;
Githubでも議論されているように、まだ細かい通知には対応していないと書いてあります。
なのでActivity, Fragment側で notifyItemRemoved() を呼んでも反応しないわけですね..。