recyclerView动画解读
来源:互联网 发布:常用理财软件 编辑:程序博客网 时间:2024/06/07 12:04
由于recyclerView有动画的情况会创建双倍的viewHolder,没有了解的,可以看看我的上一篇 为什么选择放弃recyclerView ,可是如果没有动画,item的变化太突兀了,那么这个需求就这样出来了,如何不用recyclerView的默认动画实现动画
继承ItemAnimator或者SimpleItemAnimator
我仿佛在逗我笑,就算继承了,还是要调用setAnimator方法,这样还是会创建viewHolder
那么,自己给view设定动画是否可以呢?
我们知道,recyclerView是通过notifyItem来改变item的状态的,这就是传说中的观察者模式,那么我们没有
notifyItemChanged,就算设置了view的动画,但是item没有改变,高度也不会变化。
少年, 你还年轻,跟着page继续解读。那么从最基础的开始
recyclerView中用到animator的地方有什么需要关注的地方
- 首先设置:setItemAnimator,这个似乎没什么看的
public void setItemAnimator(ItemAnimator animator) { if (mItemAnimator != null) { mItemAnimator.endAnimations(); mItemAnimator.setListener(null); } mItemAnimator = animator; if (mItemAnimator != null) { mItemAnimator.setListener(mItemAnimatorListener); } }
嗯,重新设置的时候把listener给取消
2. 接下来我们看看这个animator在哪里初始化的
ItemAnimator mItemAnimator = new DefaultItemAnimator();
嗯,有一个默认的动画
3. 动画是在哪开启的呢?
private Runnable mItemAnimatorRunner = new Runnable() { @Override public void run() { if (mItemAnimator != null) { mItemAnimator.runPendingAnimations(); } mPostedAnimatorRunner = false; } };
交给runnable去执行
private void postAnimationRunner() { if (!mPostedAnimatorRunner && mIsAttached) { ViewCompat.postOnAnimation(this, mItemAnimatorRunner); mPostedAnimatorRunner = true; } } private void animateAppearance(@NonNull ViewHolder itemHolder, @Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo) { itemHolder.setIsRecyclable(false); if (mItemAnimator.animateAppearance(itemHolder, preLayoutInfo, postLayoutInfo)) { postAnimationRunner(); } } private void animateDisappearance(@NonNull ViewHolder holder, @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo) { addAnimatingView(holder); holder.setIsRecyclable(false); if (mItemAnimator.animateDisappearance(holder, preLayoutInfo, postLayoutInfo)) { postAnimationRunner(); } } private void animateChange(@NonNull ViewHolder oldHolder, @NonNull ViewHolder newHolder, @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo, boolean oldHolderDisappearing, boolean newHolderDisappearing) { oldHolder.setIsRecyclable(false); if (oldHolderDisappearing) { addAnimatingView(oldHolder); } if (oldHolder != newHolder) { if (newHolderDisappearing) { addAnimatingView(newHolder); } oldHolder.mShadowedHolder = newHolder; // old holder should disappear after animation ends addAnimatingView(oldHolder); mRecycler.unscrapView(oldHolder); newHolder.setIsRecyclable(false); newHolder.mShadowingHolder = oldHolder; } if (mItemAnimator.animateChange(oldHolder, newHolder, preInfo, postInfo)) { postAnimationRunner(); } }
有三个地方调用到了postAnimationRunner,要继续跟踪下去,略微复杂,page还无法做到三路线程同时运行,so,先缓一缓,我们先看看这个动画到底是做了什么的。
动画的内容
// 清除 private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>(); // 添加 private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<>(); // 移动 private ArrayList<MoveInfo> mPendingMoves = new ArrayList<>(); // 改变 private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>(); private ArrayList<ArrayList<ViewHolder>> mAdditionsList = new ArrayList<>(); private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>(); private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>(); private ArrayList<ViewHolder> mAddAnimations = new ArrayList<>(); private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<>(); private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<>(); private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<>(); private static class MoveInfo { public ViewHolder holder; public int fromX, fromY, toX, toY; private MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) { this.holder = holder; this.fromX = fromX; this.fromY = fromY; this.toX = toX; this.toY = toY; } } private static class ChangeInfo { public ViewHolder oldHolder, newHolder; public int fromX, fromY, toX, toY; private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) { this.oldHolder = oldHolder; this.newHolder = newHolder; } private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY, int toX, int toY) { this(oldHolder, newHolder); this.fromX = fromX; this.fromY = fromY; this.toX = toX; this.toY = toY; } }
从这里可以看到,这个animator对所有的viewHolder都有一个缓存
@Override public void runPendingAnimations() { boolean removalsPending = !mPendingRemovals.isEmpty(); boolean movesPending = !mPendingMoves.isEmpty(); boolean changesPending = !mPendingChanges.isEmpty(); boolean additionsPending = !mPendingAdditions.isEmpty(); if (!removalsPending && !movesPending && !additionsPending && !changesPending) { // nothing to animate return; } // First, remove stuff for (ViewHolder holder : mPendingRemovals) { animateRemoveImpl(holder); } mPendingRemovals.clear(); // Next, move stuff if (movesPending) { final ArrayList<MoveInfo> moves = new ArrayList<>(); moves.addAll(mPendingMoves); mMovesList.add(moves); mPendingMoves.clear(); Runnable mover = new Runnable() { @Override public void run() { for (MoveInfo moveInfo : moves) { animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX, moveInfo.toY); } moves.clear(); mMovesList.remove(moves); } }; if (removalsPending) { View view = moves.get(0).holder.itemView; ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration()); } else { mover.run(); } } // Next, change stuff, to run in parallel with move animations if (changesPending) { final ArrayList<ChangeInfo> changes = new ArrayList<>(); changes.addAll(mPendingChanges); mChangesList.add(changes); mPendingChanges.clear(); Runnable changer = new Runnable() { @Override public void run() { for (ChangeInfo change : changes) { animateChangeImpl(change); } changes.clear(); mChangesList.remove(changes); } }; if (removalsPending) { ViewHolder holder = changes.get(0).oldHolder; ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration()); } else { changer.run(); } } // Next, add stuff if (additionsPending) { final ArrayList<ViewHolder> additions = new ArrayList<>(); additions.addAll(mPendingAdditions); mAdditionsList.add(additions); mPendingAdditions.clear(); Runnable adder = new Runnable() { public void run() { for (ViewHolder holder : additions) { animateAddImpl(holder); } additions.clear(); mAdditionsList.remove(additions); } }; if (removalsPending || movesPending || changesPending) { long removeDuration = removalsPending ? getRemoveDuration() : 0; long moveDuration = movesPending ? getMoveDuration() : 0; long changeDuration = changesPending ? getChangeDuration() : 0; long totalDelay = removeDuration + Math.max(moveDuration, changeDuration); View view = additions.get(0).itemView; ViewCompat.postOnAnimationDelayed(view, adder, totalDelay); } else { adder.run(); } } }
先移除,然后移动,再然后改变,最后添加。
在这些操作中,都可以看见循环的存在
我竟然在endAnimation中发现了一个todo
// TODO if some other animations are chained to end, how do we cancel them as well?
大致介绍完,我们具体来看看每个操作都做了啥
移除
// First, remove stuff for (ViewHolder holder : mPendingRemovals) { animateRemoveImpl(holder); } mPendingRemovals.clear(); private void animateRemoveImpl(final ViewHolder holder) { final View view = holder.itemView; final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); mRemoveAnimations.add(holder); animation.setDuration(getRemoveDuration()) .alpha(0).setListener(new VpaListenerAdapter() { @Override public void onAnimationStart(View view) { dispatchRemoveStarting(holder); } @Override public void onAnimationEnd(View view) { animation.setListener(null); ViewCompat.setAlpha(view, 1); dispatchRemoveFinished(holder); mRemoveAnimations.remove(holder); dispatchFinishedWhenDone(); } }).start(); }
只是一个简单的alpha 变为0,在动画结束后又设置alpha为1
这不相当于没有改变吗?少年,你还是太简单了,如果这个view不在这上面了,那设置alpha=1又有什么关系?当然这只是我的一个推断而已,具体是否是这样,之后再看。
这个animatorRemove方法是在animateDisappearance(simpleItemAnimator类)中调用的,而这个方法又是在这调用的
private void animateDisappearance(@NonNull ViewHolder holder, @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo) { addAnimatingView(holder); holder.setIsRecyclable(false); if (mItemAnimator.animateDisappearance(holder, preLayoutInfo, postLayoutInfo)) { postAnimationRunner(); } }
这个方法是返回true的,
@Override public boolean animateRemove(final ViewHolder holder) { resetAnimation(holder); mPendingRemovals.add(holder); return true; }
也就是说,在动画开启前,先把viewHolder加入animator的缓存集合中,再开启动画
先到这里吧,国庆之后再继续
- recyclerView动画解读
- RecyclerView.ItemAnimator终极解读(三)--继承DefaultItemAnimator实现自定义动画
- RecyclerView动画
- RecyclerView之动画效果
- InstaMaterial:正确处理RecyclerView动画
- RecyclerView动画集合
- recyclerview item动画
- RecyclerView自定义进入动画
- RecyclerView加载动画
- RecyclerView Item加载动画
- RecyclerView交互动画
- recyclerView 添加动画
- RecyclerView拖拽Item动画
- 解读核心动画类
- 对RecyclerView Item做动画
- 对RecyclerView Item做动画
- RecyclerView局部刷新动画屏蔽
- RecyclerView item刷新动画问题
- [转]数据结构中常见的树(BST二叉…
- Android开发中屏幕适配解决方案
- c语言中的字符操作
- 【HDU 5908 Abelian Period】
- Java基本集合类关系图
- recyclerView动画解读
- JavaRTTI和反射基本讲解
- Android笔试面试题一(常考选择填空)
- MFC 缩放和显示IplImage
- 利用string 字符串拷贝
- C语言初学者感想
- a+b (c语言)
- cmd下javac 错误: 编码GBK的不可映射字符
- ANGULARJS表单的错误处理