1、Recyclerview回收机制:
自定义LayoutManager时需要将不需要的View进行回收,在需要使用View时通过getViewForPosition获取View,这个View可能是之前回收的View,也可能是新new出来的,具体操作由recyclerView的recycler实现。
recyclerView内部有两个缓存:scrap和recycler。scrap缓存的View是无需重新绑定数据,可以直接使用。recycler缓存的View则需要重新绑定数据。
2、自定义LayoutManager
(1)继承RecyclerView.LayoutManager,重写四个方法
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
接下来重写onLayoutChildren对子View进行布局,在此方法里不要layout出所有的View,要将不在屏幕内的View回收
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
super.onLayoutChildren(recycler, state);
if (getItemCount() < 0) {
return;
}
if (state.isPreLayout()) {
return;
}
//缓存所有的View到scrap中
detachAndScrapAttachedViews(recycler);
int offSetY = 0;
totalHeight = 0;
for (int i = 0; i < getItemCount(); i++) {
//取出缓存的View
View view = recycler.getViewForPosition(i);
//把View加到recyclerview中
addView(view);
measureChildWithMargins(view, 0, 0);
int width = getDecoratedMeasuredWidth(view);
int height = getDecoratedMeasuredHeight(view);
offSetY += height;
totalHeight += height;
Rect frame = allItemFrames.get(i);
if (frame == null) {
frame = new Rect();
}
//保存每个View的边界rect
frame.set(0, offSetY, width, offSetY + height);
allItemFrames.put(i, frame);
}
recycleAndFillItems(recycler, state);
}
private void recycleAndFillItems(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (state.isPreLayout()) {
return;
}
//当前屏幕显示的区域
Rect displayFrame = new Rect(0, verticalScrollOffset, getHorizontalSpace(), verticalScrollOffset + getVerticalSpace());
//将滑出屏幕的View进行回收
Rect childFrame = new Rect();
for (int i = 0; i < getItemCount(); i++) {
View child = getChildAt(i);
if (child != null) {
childFrame.left = getDecoratedLeft(child);
childFrame.top = getDecoratedTop(child);
childFrame.right = getDecoratedRight(child);
childFrame.bottom = getDecoratedBottom(child);
if (!Rect.intersects(displayFrame, childFrame)) {
removeAndRecycleView(child, recycler);
}
}
}
//重新布局在屏幕上的View
for (int i = 0; i < getItemCount(); i++) {
if (Rect.intersects(displayFrame, allItemFrames.get(i))) {
View scrap = recycler.getViewForPosition(i);
measureChildWithMargins(scrap, 0, 0);
//scrap.setTranslationX(getWidth()/2);
addView(scrap);
Rect frame = allItemFrames.get(i);
layoutDecorated(scrap, frame.left, frame.top - verticalScrollOffset, frame.right, frame.bottom - verticalScrollOffset);
}
}
}
然后实现垂直滚动:
@Override
public boolean canScrollVertically() {
return true;
}
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
detachAndScrapAttachedViews(recycler);
int realScrollDistance = dy;
//边界修复
if (verticalScrollOffset + dy < 0) {//上边界
realScrollDistance = -verticalScrollOffset;
} else if (verticalScrollOffset + dy > totalHeight - getVerticalSpace()) {//下边界
realScrollDistance = totalHeight - getVerticalSpace() - verticalScrollOffset;
}
verticalScrollOffset += realScrollDistance;
//移动子View
offsetChildrenVertical(-realScrollDistance);
//填充数据
recycleAndFillItems(recycler, state);
return realScrollDistance;
}
代码地址:自定义LayoutManager