RecyclerView.Adapter の notifyItemChanged() や notifyItemRangeChanged() が呼ばれると、RecyclerView.AdapterDataObserver を通して DefaultItemAnimator の animateChange() が呼ばれます。 ここのコードを見ると
- @Override
- public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
- int fromX, int fromY, int toX, int toY) {
- if (oldHolder == newHolder) {
- // Don't know how to run change animations when the same view holder is re-used.
- // run a move animation to handle position changes.
- return animateMove(oldHolder, fromX, fromY, toX, toY);
- }
- final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView);
- final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView);
- final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
- resetAnimation(oldHolder);
- int deltaX = (int) (toX - fromX - prevTranslationX);
- int deltaY = (int) (toY - fromY - prevTranslationY);
- // recover prev translation state after ending animation
- ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX);
- ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY);
- ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
- if (newHolder != null) {
- // carry over translation values
- resetAnimation(newHolder);
- ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
- ViewCompat.setTranslationY(newHolder.itemView, -deltaY);
- ViewCompat.setAlpha(newHolder.itemView, 0);
- }
- mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
- return true;
- }
そのためレイアウト上の一部分だけを変更するとき(例えば写真のグリッド上にあるお気に入りマークの状態を更新するなど)に notifyItemChanged() を呼ぶと、アルファの処理が入るのでちらつきます。
これを防ぐにはアルファの処理が入らないパス、つまり newHolder として oldHolder と同じインスタンスが渡されるようになればいいわけです。そもそもレイアウトに変更がないのであればインスタンスを再利用しないのは無駄です。
これを切り替えるのが ItemAnimator の canReuseUpdatedViewHolder() です。 デフォルトでは true つまり再利用するようになっています。 ではどこで false が返るように変わったかというと DefaultItemAnimator の親クラスの SimpleItemAnimator です。
- abstract public class SimpleItemAnimator extends RecyclerView.ItemAnimator {
- ...
- boolean mSupportsChangeAnimations = true;
- @SuppressWarnings("unused")
- public boolean getSupportsChangeAnimations() {
- return mSupportsChangeAnimations;
- }
- public void setSupportsChangeAnimations(boolean supportsChangeAnimations) {
- mSupportsChangeAnimations = supportsChangeAnimations;
- }
- @Override
- public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
- return !mSupportsChangeAnimations || viewHolder.isInvalid();
- }
- ...
- }
- ((DefaultItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
0 件のコメント:
コメントを投稿