下面列出了androidx.recyclerview.widget.RecyclerView#SCROLL_STATE_DRAGGING 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (isEnabled()) {
switch (newState) {
case RecyclerView.SCROLL_STATE_DRAGGING:
getHandler().removeCallbacks(mScrollbarHider);
cancelAnimation(mScrollbarAnimator);
if (!isViewVisible(mScrollbar)) {
showScrollbar();
}
break;
case RecyclerView.SCROLL_STATE_IDLE:
if (mFadeScrollbar && !mHandleView.isSelected()) {
getHandler().postDelayed(mScrollbarHider, sScrollbarHideDelay);
}
break;
}
}
}
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
if (mScrollingListener == null) {
return;
}
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (!recyclerView.canScrollVertically(1)) {
//是否能向下滚动,false 表示已经滚动到底部
mScrollingListener.onScrollDown(recyclerView);
} else if (!recyclerView.canScrollVertically(-1)) {
//是否能向上滚动,false 表示已经滚动到顶部
mScrollingListener.onScrollTop(recyclerView);
}
} else if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
//正在滚动中
mScrollingListener.onScrolling(recyclerView);
}
}
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (isEnabled()) {
switch (newState) {
case RecyclerView.SCROLL_STATE_DRAGGING:
getHandler().removeCallbacks(mScrollbarHider);
cancelAnimation(mScrollbarAnimator);
if (!isViewVisible(mScrollbar)) {
showScrollbar();
}
break;
case RecyclerView.SCROLL_STATE_IDLE:
if (mFadeScrollbar && !mHandleView.isSelected()) {
getHandler().postDelayed(mScrollbarHider, sScrollbarHideDelay);
}
break;
}
}
}
@Override
public void onScrollStateChanged(int state) {
if (mCurrentScrollState == RecyclerView.SCROLL_STATE_IDLE && mCurrentScrollState != state) {
mScrollStateListener.onScrollStart();
}
if (state == RecyclerView.SCROLL_STATE_IDLE) {
//Scroll is not finished until current view is centered
boolean isScrollEnded = onScrollEnd();
if (isScrollEnded) {
mScrollStateListener.onScrollEnd();
} else {
//Scroll continues and we don't want to set mCurrentScrollState to STATE_IDLE,
//because this will then trigger .mScrollStateListener.onScrollStart()
return;
}
} else if (state == RecyclerView.SCROLL_STATE_DRAGGING) {
onDragStart();
}
mCurrentScrollState = state;
}
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
switch (state) {
case RecyclerView.SCROLL_STATE_DRAGGING:
//当手指按下时,停止当前正在播放的动画
cancelAnimator();
break;
case RecyclerView.SCROLL_STATE_IDLE:
//当列表滚动停止后,判断一下自动选中是否打开
if (isAutoSelect) {
//找到离目标落点最近的item索引
smoothScrollToPosition(findShouldSelectPosition());
}
break;
default:
break;
}
}
@Override
public final void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
switch (newState) {
case RecyclerView.SCROLL_STATE_IDLE:
isCanScrolledCallback = false;
if (isIdleCallBack()) {
if (callbackType == 1) {
onScrolledToTop();
} else if (callbackType == 2) {
onScrolledToBottom();
}
}
break;
case RecyclerView.SCROLL_STATE_DRAGGING:
isCanScrolledCallback = true;
break;
}
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (AppConfig.INSTANCE.getBoolean(recyclerView.getContext(), AppConfig.Key.SCROLLING_PAUSE_LOAD) && recyclerView.getAdapter() != null) {
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
sketch.getConfiguration().setPauseLoadEnabled(true);
} else if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (sketch.getConfiguration().isPauseLoadEnabled()) {
sketch.getConfiguration().setPauseLoadEnabled(false);
recyclerView.getAdapter().notifyDataSetChanged();
}
}
}
if (recyclerScrollListener != null) {
recyclerScrollListener.onScrollStateChanged(recyclerView, newState);
}
}
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
conversationDateHeader.show();
} else if (newState == RecyclerView.SCROLL_STATE_IDLE) {
conversationDateHeader.hide();
}
}
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
switch (newState) {
//当屏幕滚动且用户使用的触碰或手指还在屏幕上,停止加载图片
case RecyclerView.SCROLL_STATE_DRAGGING:
//由于用户的操作,屏幕产生惯性滑动,停止加载图片
case RecyclerView.SCROLL_STATE_SETTLING:
Glide.with(mActivity).pauseRequests();
break;
case RecyclerView.SCROLL_STATE_IDLE:
Glide.with(mActivity).resumeRequests();
}
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (recyclerView.isEnabled()) {
switch (newState) {
case RecyclerView.SCROLL_STATE_DRAGGING:
handler.removeCallbacks(mScrollbarHider);
if (mScrollbar.getVisibility() != View.VISIBLE) {
Utility.cancelAnimation(mScrollbarAnimator);
if (!Utility.isViewVisible(mScrollbar) && (recyclerView.computeVerticalScrollRange()
- mViewHeight > 0)) {
mScrollbarAnimator = Utility.showScrollbar(mScrollbar, Pix.this);
}
}
break;
case RecyclerView.SCROLL_STATE_IDLE:
if (mHideScrollbar && !mHandleView.isSelected()) {
handler.postDelayed(mScrollbarHider, sScrollbarHideDelay);
}
break;
default:
break;
}
}
}
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
state = newState;
if (state == RecyclerView.SCROLL_STATE_DRAGGING) {
isDrag = true;
}
if (state == RecyclerView.SCROLL_STATE_IDLE) {
isDrag = false;
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager == null) {
return;
}
if (mSnapHelper == null) {
return;
}
View snap = mSnapHelper.findSnapView(layoutManager);
if (snap == null) {
return;
}
int selectedPosition = layoutManager.getPosition(snap);
if (mOnPageChangeListener != null && selectedPosition != mCurItem) {
mCurItem = selectedPosition;
mOnPageChangeListener.onPageSelected(mCurItem);
}
}
}
@Override
public void onScrollStateChanged(int state) {
if (state == RecyclerView.SCROLL_STATE_DRAGGING) {
needSnap = true;
}
super.onScrollStateChanged(state);
}
/**
* Checks whether we should select a View for swiping.
*/
boolean checkSelectForSwipe(int action, MotionEvent motionEvent, int pointerIndex) {
if (mSelected != null || action != MotionEvent.ACTION_MOVE
|| mActionState == ACTION_STATE_DRAG || !mCallback.isItemViewSwipeEnabled()) {
return false;
}
if (mRecyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) {
return false;
}
final RecyclerView.ViewHolder vh = findSwipedView(motionEvent);
if (vh == null) {
return false;
}
final int movementFlags = mCallback.getAbsoluteMovementFlags(mRecyclerView, vh);
final int swipeFlags = (movementFlags & ACTION_MODE_SWIPE_MASK)
>> (DIRECTION_FLAG_COUNT * ACTION_STATE_SWIPE);
if (swipeFlags == 0) {
return false;
}
// mDx and mDy are only set in allowed directions. We use custom x/y here instead of
// updateDxDy to avoid swiping if user moves more in the other direction
final float x = motionEvent.getX(pointerIndex);
final float y = motionEvent.getY(pointerIndex);
// Calculate the distance moved
final float dx = x - mInitialTouchX;
final float dy = y - mInitialTouchY;
// swipe target is chose w/o applying flags so it does not really check if swiping in that
// direction is allowed. This why here, we use mDx mDy to check slope value again.
final float absDx = Math.abs(dx);
final float absDy = Math.abs(dy);
if (absDx < mSlop && absDy < mSlop) {
return false;
}
if (absDx > absDy) {
if (dx < 0 && (swipeFlags & LEFT) == 0) {
return false;
}
if (dx > 0 && (swipeFlags & RIGHT) == 0) {
return false;
}
} else {
if (dy < 0 && (swipeFlags & UP) == 0) {
return false;
}
if (dy > 0 && (swipeFlags & DOWN) == 0) {
return false;
}
}
mDx = mDy = 0f;
mActivePointerId = motionEvent.getPointerId(0);
select(vh, ACTION_STATE_SWIPE, false);
return true;
}
/**
* Checks whether we should select a View for swiping.
*/
private boolean checkSelectForSwipe(int action, MotionEvent motionEvent, int pointerIndex) {
if (mSelected != null || action != MotionEvent.ACTION_MOVE
|| mActionState == ACTION_STATE_DRAG || !mCallback.isItemViewSwipeEnabled()) {
return false;
}
if (mRecyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) {
return false;
}
final ViewHolder vh = findSwipedView(motionEvent);
if (vh == null) {
return false;
}
final int movementFlags = mCallback.getAbsoluteMovementFlags(mRecyclerView, vh);
final int swipeFlags = (movementFlags & ACTION_MODE_SWIPE_MASK)
>> (DIRECTION_FLAG_COUNT * ACTION_STATE_SWIPE);
if (swipeFlags == 0) {
return false;
}
// mDx and mDy are only set in allowed directions. We use custom x/y here instead of
// updateDxDy to avoid swiping if user moves more in the other direction
final float x = MotionEventCompat.getX(motionEvent, pointerIndex);
final float y = MotionEventCompat.getY(motionEvent, pointerIndex);
// Calculate the distance moved
final float dx = x - mInitialTouchX;
final float dy = y - mInitialTouchY;
// swipe target is chose w/o applying flags so it does not really check if swiping in that
// direction is allowed. This why here, we use mDx mDy to check slope value again.
final float absDx = Math.abs(dx);
final float absDy = Math.abs(dy);
if (absDx < mSlop && absDy < mSlop) {
return false;
}
if (absDx > absDy) {
if (dx < 0 && (swipeFlags & LEFT) == 0) {
return false;
}
if (dx > 0 && (swipeFlags & RIGHT) == 0) {
return false;
}
} else {
if (dy < 0 && (swipeFlags & UP) == 0) {
return false;
}
if (dy > 0 && (swipeFlags & DOWN) == 0) {
return false;
}
}
mDx = mDy = 0f;
mActivePointerId = MotionEventCompat.getPointerId(motionEvent, 0);
select(vh, ACTION_STATE_SWIPE);
if (mPreOpened != null && mPreOpened != vh && vh != null) {
closeOpenedPreItem();
}
return true;
}
private void updateScrollState(int scrollState)
{
int firstVisibleP = RecyclerView.NO_POSITION;
int firstCompleteVisibleP = RecyclerView.NO_POSITION;
if (mLayoutManager instanceof LinearLayoutManager)
{
firstVisibleP = ((LinearLayoutManager) mLayoutManager).findFirstVisibleItemPosition();
firstCompleteVisibleP = ((LinearLayoutManager) mLayoutManager).findFirstCompletelyVisibleItemPosition();
} else if (mLayoutManager instanceof GridLayoutManager)
{
firstVisibleP = ((GridLayoutManager) mLayoutManager).findFirstVisibleItemPosition();
firstCompleteVisibleP = ((GridLayoutManager) mLayoutManager).findFirstCompletelyVisibleItemPosition();
} else if (mLayoutManager instanceof StaggeredGridLayoutManager)
{
firstVisibleP = ((StaggeredGridLayoutManager) mLayoutManager).findFirstVisibleItemPositions(null)[0];
firstCompleteVisibleP = ((StaggeredGridLayoutManager) mLayoutManager).findFirstCompletelyVisibleItemPositions(null)[0];
}
//需要隐藏悬浮布局的时机
if (mFirstStickyPosition == RecyclerView.NO_POSITION || firstVisibleP == RecyclerView.NO_POSITION
|| firstVisibleP < mFirstStickyPosition)
{
setVisibility(GONE);
mCurrentIndicatePosition = RecyclerView.NO_POSITION;
return;
}
setVisibility(VISIBLE);
if (firstCompleteVisibleP == RecyclerView.NO_POSITION && firstVisibleP >= mFirstStickyPosition)
{
firstCompleteVisibleP = firstVisibleP;
}
//两个Section相顶效果
if (mAdapter.isSectionLabelViewType(mAdapter.getItemViewType(firstCompleteVisibleP)))
{
int top = mLayoutManager.findViewByPosition(firstCompleteVisibleP).getTop();
if (top >= 0 && top < mStickyHeight)
{
setY(top - mStickyHeight);
} else
{
setY(0);
}
} else
{
setY(0);
}
if (scrollState == RecyclerView.SCROLL_STATE_IDLE || scrollState == RecyclerView.SCROLL_STATE_DRAGGING)
{
//停止或者手触摸拉动的情况
updateStickyLayout(getLastSectionPosition(firstVisibleP));
} else
{
//惯性滑动的情况
if (firstVisibleP < mAdapterItemCount && firstCompleteVisibleP < mAdapterItemCount)
{
if (firstVisibleP > mCurrentIndicatePosition && firstVisibleP != RecyclerView.NO_POSITION
&& mAdapter.isSectionLabelViewType(mAdapter.getItemViewType(firstVisibleP)))
{
updateStickyLayout(firstVisibleP);
} else if (firstVisibleP < mCurrentIndicatePosition && firstCompleteVisibleP != RecyclerView.NO_POSITION
&& mAdapter.isSectionLabelViewType(mAdapter.getItemViewType(firstCompleteVisibleP)))
{
updateStickyLayout(getLastStickyPosition(mCurrentIndicatePosition));
}
}
}
}
/**
* Checks whether we should select a View for swiping.
*/
private boolean checkSelectForSwipe(int action, MotionEvent motionEvent, int pointerIndex) {
if (selected != null || action != MotionEvent.ACTION_MOVE) {
return false;
}
if (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) {
return false;
}
final RecyclerView.ViewHolder vh = findSwipedView(motionEvent);
if (vh == null) {
return false;
}
final int movementFlags = callback.getAbsMovementFlags(recyclerView, vh);
final int swipeFlags =
(movementFlags & ACTION_MODE_SWIPE_MASK) >> (DIRECTION_FLAG_COUNT * ACTION_STATE_SWIPE);
if (swipeFlags == 0) {
return false;
}
// dX and dY are only set in allowed directions. We use custom x/y here instead of
// updateDxDy to avoid swiping if user moves more in the other direction
final float x = motionEvent.getX(pointerIndex);
final float y = motionEvent.getY(pointerIndex);
// Calculate the distance moved
final float dx = x - initialTouchX;
final float dy = y - initialTouchY;
// swipe target is chose w/o applying flags so it does not really check if swiping in that
// direction is allowed. This why here, we use dX dY to check slope value again.
final float absDx = Math.abs(dx);
final float absDy = Math.abs(dy);
if (absDx < slop && absDy < slop) {
return false;
}
if (absDx > absDy) {
if (dx < 0 && (swipeFlags & LEFT) == 0) {
return false;
}
if (dx > 0 && (swipeFlags & RIGHT) == 0) {
return false;
}
} else {
if (dy < 0 && (swipeFlags & UP) == 0) {
return false;
}
if (dy > 0 && (swipeFlags & DOWN) == 0) {
return false;
}
}
dX = dY = 0f;
activePointerId = motionEvent.getPointerId(0);
select((SwipeOpenViewHolder) vh, ACTION_STATE_SWIPE);
return true;
}
/**
* Checks whether we should select a View for swiping.
*/
boolean checkSelectForSwipe(int action, MotionEvent motionEvent, int pointerIndex) {
if (mSelected != null || action != MotionEvent.ACTION_MOVE
|| mActionState == ACTION_STATE_DRAG || !mCallback.isItemViewSwipeEnabled()) {
return false;
}
if (mRecyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) {
return false;
}
final ViewHolder vh = findSwipedView(motionEvent);
if (vh == null) {
return false;
}
final int movementFlags = mCallback.getAbsoluteMovementFlags(mRecyclerView, vh);
final int swipeFlags = (movementFlags & ACTION_MODE_SWIPE_MASK)
>> (DIRECTION_FLAG_COUNT * ACTION_STATE_SWIPE);
if (swipeFlags == 0) {
return false;
}
// mDx and mDy are only set in allowed directions. We use custom x/y here instead of
// updateDxDy to avoid swiping if user moves more in the other direction
final float x = motionEvent.getX(pointerIndex);
final float y = motionEvent.getY(pointerIndex);
// Calculate the distance moved
final float dx = x - mInitialTouchX;
final float dy = y - mInitialTouchY;
// swipe target is chose w/o applying flags so it does not really check if swiping in that
// direction is allowed. This why here, we use mDx mDy to check slope value again.
final float absDx = Math.abs(dx);
final float absDy = Math.abs(dy);
if (absDx < mSlop && absDy < mSlop) {
return false;
}
if (absDx > absDy) {
if (dx < 0 && (swipeFlags & LEFT) == 0) {
return false;
}
if (dx > 0 && (swipeFlags & RIGHT) == 0) {
return false;
}
} else {
if (dy < 0 && (swipeFlags & UP) == 0) {
return false;
}
if (dy > 0 && (swipeFlags & DOWN) == 0) {
return false;
}
}
mDx = mDy = 0f;
mActivePointerId = motionEvent.getPointerId(0);
select(vh, ACTION_STATE_SWIPE);
return true;
}
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (!Preferences.isViewerSwipeToTurn() || !isScrollEnabled) {
recyclerView.stopScroll();
return;
}
LinearLayoutManager llm = (LinearLayoutManager) recyclerView.getLayoutManager();
if (llm != null) {
if (RecyclerView.SCROLL_STATE_DRAGGING == newState) {
dragStartPositionX = recyclerView.computeHorizontalScrollOffset();
dragStartPositionY = recyclerView.computeVerticalScrollOffset();
isSettlingX = false;
isSettlingY = false;
} else if (RecyclerView.SCROLL_STATE_SETTLING == newState) {
// If the settling position is different from the original position, ignore that scroll
// (e.g. snapping back to the original position after a small scroll)
if (recyclerView.computeHorizontalScrollOffset() != dragStartPositionX)
isSettlingX = true;
if (recyclerView.computeVerticalScrollOffset() != dragStartPositionY)
isSettlingY = true;
} else if (RecyclerView.SCROLL_STATE_IDLE == newState) {
// Don't do anything if we're not on a boundary
if (!(llm.findLastVisibleItemPosition() == llm.getItemCount() - 1 || 0 == llm.findFirstVisibleItemPosition()))
return;
if (recyclerView.computeHorizontalScrollOffset() == dragStartPositionX && !isSettlingX && llm.canScrollHorizontally()) {
if (0 == dragStartPositionX && !llm.getReverseLayout())
onStartOutOfBoundScroll.run();
else if (0 == dragStartPositionX) onEndOutOfBoundScroll.run();
else if (llm.getReverseLayout()) onStartOutOfBoundScroll.run();
else onEndOutOfBoundScroll.run();
}
if (recyclerView.computeVerticalScrollOffset() == dragStartPositionY && !isSettlingY && llm.canScrollVertically()) {
if (0 == dragStartPositionY && !llm.getReverseLayout())
onStartOutOfBoundScroll.run();
else if (0 == dragStartPositionY) onEndOutOfBoundScroll.run();
else if (llm.getReverseLayout()) onStartOutOfBoundScroll.run();
else onEndOutOfBoundScroll.run();
}
}
}
}
/**
* This moves to the specified time in the view. If the time is not already
* in range it will move the list so that the first of the month containing
* the time is at the top of the view. If the new time is already in view
* the list will not be scrolled unless forceScroll is true. This time may
* optionally be highlighted as selected as well.
*
* @param day The day to move to
* @param animate Whether to scroll to the given time or just redraw at the
* new location
* @param setSelected Whether to set the given time as selected
* @param forceScroll Whether to recenter even if the time is already
* visible
* @return Whether or not the view animated to the new location
*/
public boolean goTo(MonthAdapter.CalendarDay day, boolean animate, boolean setSelected, boolean forceScroll) {
// Set the selected day
if (setSelected) {
mSelectedDay.set(day);
}
mTempDay.set(day);
int minMonth = mController.getStartDate().get(Calendar.MONTH);
final int position = (day.year - mController.getMinYear())
* MonthAdapter.MONTHS_IN_YEAR + day.month - minMonth;
View child;
int i = 0;
int top = 0;
// Find a child that's completely in the view
do {
child = getChildAt(i++);
if (child == null) {
break;
}
top = child.getTop();
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "child at " + (i - 1) + " has top " + top);
}
} while (top < 0);
// Compute the first and last position visible
int selectedPosition = child != null ? getChildAdapterPosition(child) : 0;
if (setSelected) {
mAdapter.setSelectedDay(mSelectedDay);
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "GoTo position " + position);
}
// Check if the selected day is now outside of our visible range
// and if so scroll to the month that contains it
if (position != selectedPosition || forceScroll) {
setMonthDisplayed(mTempDay);
mPreviousScrollState = RecyclerView.SCROLL_STATE_DRAGGING;
if (animate) {
smoothScrollToPosition(position);
if (pageListener != null) pageListener.onPageChanged(position);
return true;
} else {
postSetSelection(position);
}
} else if (setSelected) {
setMonthDisplayed(mSelectedDay);
}
return false;
}