下面列出了androidx.recyclerview.widget.RecyclerView#Recycler ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
RecyclerView.State state) {
//手指从右向左滑动,dx > 0; 手指从左向右滑动,dx < 0;
//位移0、没有子View 当然不移动
if (dx == 0 || getChildCount() == 0) {
return 0;
}
mHorizontalOffset += dx;//累加实际滑动距离
dx = fill(recycler, state, dx);
return dx;
}
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State
state) {
if (mRowHeaderRecyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE &&
!mRowHeaderRecyclerView.isScrollOthers()) {
// CellRecyclerViews should be scrolled after the RowHeaderRecyclerView.
// Because it is one of the main compared criterion to make each columns fit.
mRowHeaderRecyclerView.scrollBy(0, dy);
}
int scroll = super.scrollVerticallyBy(dy, recycler, state);
// It is important to determine right position to fit all columns which are the same y pos.
mLastDy = dy;
return scroll;
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getItemCount() == 0) {
reset();
detachAndScrapAttachedViews(recycler);
return;
}
if (state.isPreLayout()) {
// 预布局
return;
}
if (state.getItemCount() != 0 && !state.didStructureChange()) {
// 数据集未改变
if (!getState().layoutChanged) {
return;
}
}
if (getChildCount() == 0 || state.didStructureChange()) {
reset();
}
mInitialSelectedPosition = Math.min(Math.max(0, mInitialSelectedPosition), getItemCount() - 1);
detachAndScrapAttachedViews(recycler);
firstFill(recycler);
getState().layoutChanged = false;
}
private void removeAndRecyclerWithRight(RecyclerView.Recycler recycler, int rightEdge) {
View child;
for (int i = getChildCount() - 1; i >= 0; i--) {
child = getChildAt(i);
if (child != null && getDecoratedLeft(child) > rightEdge) {
// 离开屏幕右侧
removeAndRecycleView(child, recycler);
if (isLooper) {
if (mLastVisiblePosition == 0) {
mLastVisiblePosition = getItemCount();
}
}
mLastVisiblePosition--;
}
}
}
/**
* 水平填充布局测量
*
* @param recycler RecyclerView.Recycler
* @param offset 水平偏移量
*/
private void fillWithHorizontal(RecyclerView.Recycler recycler, int offset) {
final OrientationHelper orientationHelper = getOrientationHelper();
final int leftEdge = orientationHelper.getStartAfterPadding();
final int rightEdge = orientationHelper.getEndAfterPadding();
if (getChildCount() > 0) {
if (offset >= 0) {
removeAndRecyclerWithLeft(recycler, leftEdge + offset);
} else {
removeAndRecyclerWithRight(recycler, rightEdge + offset);
}
}
if (offset >= 0) {
// 右滑
fillRight(recycler, rightEdge + offset);
} else {
// 左滑
fillLeft(recycler, leftEdge + offset);
}
}
/**
* 垂直填充布局测量
*
* @param recycler RecyclerView.Recycler
* @param offset 垂直偏移量
*/
private void fillWithVertical(RecyclerView.Recycler recycler, int offset) {
final OrientationHelper orientationHelper = getOrientationHelper();
final int topEdge = orientationHelper.getStartAfterPadding();
final int bottomEdge = orientationHelper.getEndAfterPadding();
if (getChildCount() > 0) {
if (offset >= 0) {
// 下滑
removeAndRecyclerWithTop(recycler, topEdge + offset);
} else {
// 上滑
removeAndRecyclerWithBottom(recycler, bottomEdge + offset);
}
}
if (offset >= 0) {
fillBottom(recycler, bottomEdge + offset);
} else {
fillTop(recycler, topEdge + offset);
}
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (mColumnSizeChanged && mColumnSize > 0) {
int totalSpace;
if (getOrientation() == RecyclerView.VERTICAL) {
totalSpace = getWidth() - getPaddingRight() - getPaddingLeft();
} else {
totalSpace = getHeight() - getPaddingTop() - getPaddingBottom();
}
int spanCount;
switch (mStrategy) {
default:
case STRATEGY_MIN_SIZE:
spanCount = getSpanCountForMinSize(totalSpace, mColumnSize);
break;
case STRATEGY_SUITABLE_SIZE:
spanCount = getSpanCountForSuitableSize(totalSpace, mColumnSize);
break;
}
setSpanCount(spanCount);
mColumnSizeChanged = false;
if (null != mListeners) {
for (int i = 0, n = mListeners.size(); i < n; i++) {
mListeners.get(i).onUpdateSpanCount(spanCount);
}
}
}
super.onLayoutChildren(recycler, state);
}
private void layoutView(RecyclerView.Recycler recycler, int position, Point viewCenter) {
if (position < 0) return;
View v = mViewCacheArray.get(position);
if (v == null) {
v = getMeasuredChildForAdapterPosition(position, recycler);
layoutDecoratedWithMargins(v,
viewCenter.x - mChildHalfWidth, viewCenter.y - mChildHalfHeight,
viewCenter.x + mChildHalfWidth, viewCenter.y + mChildHalfHeight);
} else {
attachView(v);
mViewCacheArray.remove(position);
}
}
@Override
public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
super.onDetachedFromWindow(view, recycler);
// Update positions in case we need to save post-detach
updateFirstAdapterPosition();
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
// We have nothing to show for an empty data set but clear any existing views
if (getItemCount() == 0) {
detachAndScrapAttachedViews(recycler);
return;
}
mSizeCalculator.setContentWidth(getContentWidth());
mSizeCalculator.reset();
int initialTopOffset = 0;
if (getChildCount() == 0) { // First or empty layout
mFirstVisiblePosition = 0;
mFirstVisibleRow = 0;
} else { // Adapter data set changes
// Keep the existing initial position, and save off the current scrolled offset.
final View topChild = getChildAt(0);
if (mForceClearOffsets) {
initialTopOffset = 0;
mForceClearOffsets = false;
} else {
initialTopOffset = getDecoratedTop(topChild);
}
}
detachAndScrapAttachedViews(recycler);
preFillGrid(Direction.NONE, 0, initialTopOffset, recycler, state);
mPendingScrollPositionOffset = 0;
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
detachStickyHeader();
int scrolled = super.scrollHorizontallyBy(dx, recycler, state);
attachStickyHeader();
if (scrolled != 0) {
updateStickyHeader(recycler, false);
}
return scrolled;
}
@Override
public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
if (positioner != null) {
positioner.clearVisibilityObserver();
}
super.onDetachedFromWindow(view, recycler);
}
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
return scrollBy(dx, recycler);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
super.onLayoutChildren(recycler, state);
scrollHorizontallyBy(0, recycler, state);
}
@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
final int widthMode = View.MeasureSpec.getMode(widthSpec);
final int heightMode = View.MeasureSpec.getMode(heightSpec);
final int widthSize = View.MeasureSpec.getSize(widthSpec);
final int heightSize = View.MeasureSpec.getSize(heightSpec);
int width = 0;
int height = 0;
int count = getItemCount();
int span = getSpanCount();
for (int i = 0; i < count; i++) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
if (getOrientation() == HORIZONTAL) {
if (i % span == 0) {
width = width + mMeasuredDimension[0];
}
if (i == 0) {
height = mMeasuredDimension[1];
}
} else {
if (i % span == 0) {
height = height + mMeasuredDimension[1];
}
if (i == 0) {
width = mMeasuredDimension[0];
}
}
}
switch (widthMode) {
case View.MeasureSpec.EXACTLY:
width = widthSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
switch (heightMode) {
case View.MeasureSpec.EXACTLY:
height = heightSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
setMeasuredDimension(width, height);
}
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getChildCount() == 0 || dy == 0) {
return 0;
}
final View topLeftView = getChildAt(0);
final View bottomRightView = getChildAt(getChildCount() - 1);
int pixelsFilled = getContentHeight();
// TODO: Split into methods, or a switch case?
if (dy > 0) {
boolean isLastChildVisible = (mFirstVisiblePosition + getChildCount()) >= getItemCount();
if (isLastChildVisible) {
// Is at end of content
pixelsFilled = Math.max(getDecoratedBottom(bottomRightView) - getContentHeight(), 0);
} else if (getDecoratedBottom(topLeftView) - dy <= 0) {
// Top row went offscreen
mFirstVisibleRow++;
pixelsFilled = preFillGrid(Direction.DOWN, Math.abs(dy), 0, recycler, state);
} else if (getDecoratedBottom(bottomRightView) - dy < getContentHeight()) {
// New bottom row came on screen
pixelsFilled = preFillGrid(Direction.DOWN, Math.abs(dy), 0, recycler, state);
}
} else {
if (mFirstVisibleRow == 0 && getDecoratedTop(topLeftView) - dy >= 0) {
// Is scrolled to top
pixelsFilled = -getDecoratedTop(topLeftView);
} else if (getDecoratedTop(topLeftView) - dy >= 0) {
// New top row came on screen
mFirstVisibleRow--;
pixelsFilled = preFillGrid(Direction.UP, Math.abs(dy), 0, recycler, state);
} else if (getDecoratedTop(bottomRightView) - dy > getContentHeight()) {
// Bottom row went offscreen
pixelsFilled = preFillGrid(Direction.UP, Math.abs(dy), 0, recycler, state);
}
}
final int scrolled = Math.abs(dy) > pixelsFilled ? (int) Math.signum(dy) * pixelsFilled : dy;
offsetChildrenVertical(-scrolled);
// Return value determines if a boundary has been reached (for edge effects and flings). If
// returned value does not match original delta (passed in), RecyclerView will draw an
// edge effect.
return scrolled;
}
@Override
protected void onFragmentReady() {
checkShowButton();
mLayoutManager =
new LinearLayoutManager(getContext()) {
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
super.onLayoutChildren(recycler, state);
int itemsShown = findLastVisibleItemPosition() - findFirstVisibleItemPosition() + 1;
if (mContactsAdapter.getItemCount() > itemsShown) {
mFastScroller.setVisibility(View.VISIBLE);
mRecyclerView.setOnScrollChangeListener(ContactsFragment.this);
} else {
mFastScroller.setVisibility(View.GONE);
}
}
};
// The list adapter
mContactsAdapter = new ContactsAdapter(getContext(), null, this, this);
mContactsAdapter.setOnContactSelectedListener(this);
// Recycle View
mRecyclerView.setAdapter(mContactsAdapter);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
switch (newState) {
case RecyclerView.SCROLL_STATE_IDLE:
mSharedDialViewModel.setIsOutOfFocus(false);
break;
case RecyclerView.SCROLL_STATE_DRAGGING:
mSharedDialViewModel.setIsOutOfFocus(true);
mSharedSearchViewModel.setIsFocused(false);
break;
case RecyclerView.SCROLL_STATE_SETTLING:
mSharedDialViewModel.setIsOutOfFocus(true);
mSharedSearchViewModel.setIsFocused(false);
default:
mSharedDialViewModel.setIsOutOfFocus(false);
}
}
});
// Refresh Layout
mRefreshLayout.setOnRefreshListener(() -> {
LoaderManager.getInstance(ContactsFragment.this).restartLoader(LOADER_ID, null, ContactsFragment.this);
tryRunningLoader();
});
mEmptyTitle.setText(R.string.empty_contact_title);
mEmptyDesc.setText(R.string.empty_contact_desc);
}
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
scaleVerticalChildView();
return super.scrollVerticallyBy(dy, recycler, state);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
super.onLayoutChildren(recycler, state);
if (dataSetChanged) {
removeAndRecycleAllViews(recycler);
} else {
detachAndScrapAttachedViews(recycler);
}
if (state.getItemCount() == 0 || state.isPreLayout()) {
return;
}
if (getItemCount() == 0) {
return;
}
int y = 0;
if (!getClipToPadding()) {
y += getPaddingTop();
}
int childHeight;
ViewGroup.MarginLayoutParams params;
for (int i = 0; i < getItemCount(); i ++) {
View child = recycler.getViewForPosition(i);
addView(child);
measureChildWithMargins(child, 0, 0);
childHeight = getDecoratedMeasuredHeight(child);
params = (ViewGroup.MarginLayoutParams) child.getLayoutParams();
layoutDecoratedWithMargins(
child,
getPaddingLeft(),
y,
getWidth() - getPaddingRight(),
y + childHeight + params.topMargin + params.bottomMargin
);
y += childHeight + params.topMargin + params.bottomMargin;
}
if (!getClipToPadding()) {
y += getPaddingBottom();
}
measuredHeight = y;
if (dataSetChanged) {
scrollOffset = 0;
dataSetChanged = false;
} else {
int oldOffset = scrollOffset;
scrollOffset = 0;
scrollVerticallyBy(oldOffset, recycler, state);
}
}