上篇文章主要讲的是itemView的绘制流程。
分析完上篇文章后,我又开始疑惑了,itemView的动画是如何绘制的呢 ?
从源码来分析这个问题,从上篇文章我们看到,RecyclerView 绘制的关键是onLayout 里面的position 位置确定,因此直接上源码:
@Override
protected void onLayout(boolean changed , int l , int t , int r , int b) {
eatRequestLayout();
dispatchLayout();
resumeRequestLayout(false);
mFirstLayoutComplete = true;
}
里面关键的是:
dispatchLayout()
void dispatchLayout() {
if (mAdapter == null) {
Log.e(TAG, "No adapter attached; skipping layout");
return;
}
eatRequestLayout();
// simple animations are a subset of advanced animations (which will cause a
// prelayout step)
boolean animateChangesSimple = mItemAnimator != null && mItemsAddedOrRemoved && !mItemsChanged;
final boolean animateChangesAdvanced = ENABLE_PREDICTIVE_ANIMATIONS && animateChangesSimple && predictiveItemAnimationsEnabled();
mItemsAddedOrRemoved = mItemsChanged = false;
ArrayMap<View, Rect> appearingViewInitialBounds = null;
mState.mInPreLayout = animateChangesAdvanced;
mState.mItemCount = mAdapter.getItemCount();
if (animateChangesSimple) {
// Step 0: Find out where all non-removed items are, pre-layout
mState.mPreLayoutHolderMap.clear();
mState.mPostLayoutHolderMap.clear();
final int count = getChildCount();
for (int i = 0; i < count; ++i) {
final ViewHolder holder = getChildViewHolderInt(getChildAt(i));
final View view = holder.itemView;
mState.mPreLayoutHolderMap.put(holder, new ItemHolderInfo(holder, view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), holder.mPosition));
}
}
if (animateChangesAdvanced) {
// Step 1: run prelayout: This will use the old positions of items. The layout manager
// is expected to layout everything, even removed items (though not to add removed
// items back to the container). This gives the pre-layout position of APPEARING views
// which come into existence as part of the real layout.
mInPreLayout = true;
final boolean didStructureChange = mState.mStructureChanged;
mState.mStructureChanged = false;
// temporarily disable flag because we are asking for previous layout
mLayout.onLayoutChildren(mRecycler, mState);
mState.mStructureChanged = didStructureChange;
mInPreLayout = false;
appearingViewInitialBounds = new ArrayMap<View, Rect>();
for (int i = 0; i < getChildCount(); ++i) {
boolean found = false;
final View child = getChildAt(i);
for (int j = 0; j < mState.mPreLayoutHolderMap.size(); ++j) {
final ViewHolder holder = mState.mPreLayoutHolderMap.keyAt(j);
if (holder.itemView == child) {
found = true;
continue;
}
}
if (!found) {
appearingViewInitialBounds.put(child, new Rect(child.getLeft(), child.getTop(), child.getRight(), child.getBottom()));
}
}
}
clearOldPositions();
dispatchLayoutUpdates();
mState.mItemCount = mAdapter.getItemCount();
// Step 2: Run layout
mState.mInPreLayout = false;
mLayout.onLayoutChildren(mRecycler, mState);
mState.mStructureChanged = false;
mPendingSavedState = null;
// onLayoutChildren may have caused client code to disable item animations; re-check
animateChangesSimple = animateChangesSimple && mItemAnimator != null;
if (animateChangesSimple) {
// Step 3: Find out where things are now, post-layout
int count = getChildCount();
for (int i = 0; i < count; ++i) {
final ViewHolder holder = getChildViewHolderInt(getChildAt(i));
final View view = holder.itemView;
mState.mPostLayoutHolderMap.put(holder, new ItemHolderInfo(holder, view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), holder.mPosition));
}
// Step 4: Animate DISAPPEARING and REMOVED items
final int preLayoutCount = mState.mPreLayoutHolderMap.size();
for (int i = preLayoutCount - 1; i >= 0; i--) {
final ViewHolder itemHolder = mState.mPreLayoutHolderMap.keyAt(i);
if (!mState.mPostLayoutHolderMap.containsKey(itemHolder)) {
final ItemHolderInfo disappearingItem = mState.mPreLayoutHolderMap.valueAt(i);
mState.mPreLayoutHolderMap.removeAt(i);
final View disappearingItemView = disappearingItem.holder.itemView;
removeDetachedView(disappearingItemView, false);
mRecycler.unscrapView(disappearingItem.holder);
animateDisappearance(disappearingItem);
}
}
// Step 5: Animate APPEARING and ADDED items
final int postLayoutCount = mState.mPostLayoutHolderMap.size();
if (postLayoutCount > 0) {
for (int i = postLayoutCount - 1; i >= 0; i--) {
final ViewHolder itemHolder = mState.mPostLayoutHolderMap.keyAt(i);
final ItemHolderInfo info = mState.mPostLayoutHolderMap.valueAt(i);
if ((mState.mPreLayoutHolderMap.isEmpty() || !mState.mPreLayoutHolderMap.containsKey(itemHolder))) {
mState.mPostLayoutHolderMap.removeAt(i);
final Rect initialBounds = (appearingViewInitialBounds != null) ? appearingViewInitialBounds.get(itemHolder.itemView) : null;
animateAppearance(itemHolder, initialBounds, info.left, info.top);
}
}
}
// Step 6: Animate PERSISTENT items
count = mState.mPostLayoutHolderMap.size();
for (int i = 0; i < count; ++i) {
final ViewHolder postHolder = mState.mPostLayoutHolderMap.keyAt(i);
final ItemHolderInfo postInfo = mState.mPostLayoutHolderMap.valueAt(i);
final ItemHolderInfo preInfo = mState.mPreLayoutHolderMap.get(postHolder);
if (preInfo != null && postInfo != null) {
if (preInfo.left != postInfo.left || preInfo.top != postInfo.top) {
postHolder.setIsRecyclable(false);
if (DEBUG) {
Log.d(TAG, "PERSISTENT: " + postHolder + " with view " + postHolder.itemView);
}
if (mItemAnimator.animateMove(postHolder, preInfo.left, preInfo.top, postInfo.left, postInfo.top)) {
postAnimationRunner();
}
}
}
}
}
resumeRequestLayout(false);
mLayout.removeAndRecycleScrapInt(mRecycler, !animateChangesAdvanced);
mState.mPreviousLayoutItemCount = mState.mItemCount;
mState.mDeletedInvisibleItemCountSincePreviousLayout = 0;
}
从开始进行分析,boolean animateChangesSimple = mItemAnimator != null && mItemsAddedOrRemoved && !mItemsChanged; mItemAnimator 这个参数不为空,mItemsAddedOrRemoved 表示是添加和删除了itemView追踪一下,发现他在
void updateChildViews() {
final int opCount = mPendingUpdates.size();
for (int i = 0; i < opCount; i++) {
final UpdateOp op = mPendingUpdates.get(i);
switch (op.cmd) {
case UpdateOp.ADD:
if (DEBUG) {
Log.d(TAG, "UpdateOp.ADD start=" + op.positionStart + " count=" + op.itemCount);
}
offsetPositionRecordsForInsert(op.positionStart, op.itemCount);
mItemsAddedOrRemoved = true;
break;
case UpdateOp.REMOVE:
if (DEBUG) {
Log.d(TAG, "UpdateOp.REMOVE start=" + op.positionStart + " count=" + op.itemCount);
}
for (int j = 0; j < op.itemCount; ++j) {
final ViewHolder holder = findViewHolderForPosition(op.positionStart + j, true);
if (holder != null) {
holder.setIsRecyclable(false);
}
else {
mState.mDeletedInvisibleItemCountSincePreviousLayout++;
}
}
offsetPositionRecordsForRemove(op.positionStart, op.itemCount);
mItemsAddedOrRemoved = true;
break;
case UpdateOp.UPDATE:
if (DEBUG) {
Log.d(TAG, "UpdateOp.UPDATE start=" + op.positionStart + " count=" + op.itemCount);
}
viewRangeUpdate(op.positionStart, op.itemCount);
mItemsChanged = true;
break;
}
mPendingLayoutUpdates.add(op);
// TODO: recycle the op if no animator (also don't bother stashing in pending layout updates?)
}
mPendingUpdates.clear();
}
发现在这个里面赋值为true,很明显的是UpdateOp操作为 ADD REMOVEDE 的时候,赋值为true,这里涉及到观察者模式,下篇文章会具体讲这个问题,在这里我们知道是我们手动通知了adapter 数据改变了。接着上面的讲,animateChangesSimple 为true,下面的变量animateChangesAdvanced 为true,mItemsAddedOrRemoved = mItemsChanged = false 避免下次重复执行动画的处理。
if (animateChangesSimple) {
// Step 0: Find out where all non-removed items are, pre-layout
mState.mPreLayoutHolderMap.clear();
mState.mPostLayoutHolderMap.clear();
final int count = getChildCount();
for (int i = 0; i < count; ++i) {
final ViewHolder holder = getChildViewHolderInt(getChildAt(i));
final View view = holder.itemView;
mState.mPreLayoutHolderMap.put(holder, new ItemHolderInfo(holder, view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), holder.mPosition));
}
}
因为上面我们已经确定animateChangesSimple 为true,注意: 这段 代码就是把所有的itemView的现状保存一下。
if (animateChangesAdvanced) {
// Step 1: run prelayout: This will use the old positions of items. The layout manager
// is expected to layout everything, even removed items (though not to add removed
// items back to the container). This gives the pre-layout position of APPEARING views
// which come into existence as part of the real layout.
mInPreLayout = true;
final boolean didStructureChange = mState.mStructureChanged;
mState.mStructureChanged = false;
// temporarily disable flag because we are asking for previous layout
mLayout.onLayoutChildren(mRecycler, mState);
mState.mStructureChanged = didStructureChange;
mInPreLayout = false;
appearingViewInitialBounds = new ArrayMap<View, Rect>();
for (int i = 0; i < getChildCount(); ++i) {
boolean found = false;
final View child = getChildAt(i);
for (int j = 0; j < mState.mPreLayoutHolderMap.size(); ++j) {
final ViewHolder holder = mState.mPreLayoutHolderMap.keyAt(j);
if (holder.itemView == child) {
found = true;
continue;
}
}
if (!found) {
appearingViewInitialBounds.put(child, new Rect(child.getLeft(), child.getTop(), child.getRight(), child.getBottom()));
}
}
}
里面有一段关键代码,
mLayout.onLayoutChildren(mRecycler, mState);
这个主要是重新布局,后面的for循环是为了获取新增加的itemView,存储在了 appearingViewInitialBounds这个集合中
clearOldPositions()是清除itemView的位置信息;
mState.mInPreLayout = false;
mLayout.onLayoutChildren(mRecycler, mState);
主要是调用LayoutManager 中的onlayoutChidren 方法,来为itemview 确定位置;
下面重点来了,
// Step 3: Find out where things are now, post-layout
int count = getChildCount();
for (int i = 0; i < count; ++i) {
final ViewHolder holder = getChildViewHolderInt(getChildAt(i));
final View view = holder.itemView;
mState.mPostLayoutHolderMap.put(holder, new ItemHolderInfo(holder, view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), holder.mPosition));
}
保存itemView的最终位置
下面就开始执行“删除itemView ” 时候的动画了
// Step 4: Animate DISAPPEARING and REMOVED items
final int preLayoutCount = mState.mPreLayoutHolderMap.size();
for (int i = preLayoutCount - 1; i >= 0; i--) {
final ViewHolder itemHolder = mState.mPreLayoutHolderMap.keyAt(i);
if (!mState.mPostLayoutHolderMap.containsKey(itemHolder)) {
final ItemHolderInfo disappearingItem = mState.mPreLayoutHolderMap.valueAt(i);
mState.mPreLayoutHolderMap.removeAt(i);
final View disappearingItemView = disappearingItem.holder.itemView;
removeDetachedView(disappearingItemView, false);
mRecycler.unscrapView(disappearingItem.holder);
animateDisappearance(disappearingItem);
}
}
上下的是执行那些新增加的 ItemView的动画
// Step 5: Animate APPEARING and ADDED items
final int postLayoutCount = mState.mPostLayoutHolderMap.size();
if (postLayoutCount > 0) {
for (int i = postLayoutCount - 1; i >= 0; i--) {
final ViewHolder itemHolder = mState.mPostLayoutHolderMap.keyAt(i);
final ItemHolderInfo info = mState.mPostLayoutHolderMap.valueAt(i);
if ((mState.mPreLayoutHolderMap.isEmpty() || !mState.mPreLayoutHolderMap.containsKey(itemHolder))) {
mState.mPostLayoutHolderMap.removeAt(i);
final Rect initialBounds = (appearingViewInitialBounds != null) ? appearingViewInitialBounds.get(itemHolder.itemView) : null;
animateAppearance(itemHolder, initialBounds, info.left, info.top);
}
}
}
下面执行的剩余itemView的动画(位置有可能发生了变化)
// Step 6: Animate PERSISTENT items
count = mState.mPostLayoutHolderMap.size();
for (int i = 0; i < count; ++i) {
final ViewHolder postHolder = mState.mPostLayoutHolderMap.keyAt(i);
final ItemHolderInfo postInfo = mState.mPostLayoutHolderMap.valueAt(i);
final ItemHolderInfo preInfo = mState.mPreLayoutHolderMap.get(postHolder);
if (preInfo != null && postInfo != null) {
if (preInfo.left != postInfo.left || preInfo.top != postInfo.top) {
postHolder.setIsRecyclable(false);
if (DEBUG) {
Log.d(TAG, "PERSISTENT: " + postHolder + " with view " + postHolder.itemView);
}
if (mItemAnimator.animateMove(postHolder, preInfo.left, preInfo.top, postInfo.left, postInfo.top)) {
postAnimationRunner();
}
}
}
}
至于每个itemView的动画交给了 DefaultItemAnimator 这个类进行处理,不停的更新的动画itemView的位置或者是透明度以及其他的数据。
主要的逻辑就是:
增加/删除itemView - 保留itemView 的位置 -进行预处理(测量所有itemView的位置),获取新增的itemView- 清除所有itemView的位置信息- 测量以及定位所有的itemView- 保存itemview的最终动画的位置以及其他信息- 处理删除remove的itemView- 处理被add的itemview的动画-处理剩余itemview 位置改变的itemview的动画。
上面就是动画绘制的主要过程。