前言:
一般我们用 Recycleview.smoothScrollToPosition(0)滑动到顶部,具有滚动效果,但是如果我们想滚动到任意指定位置,那么smoothScrollToPosition()就不能保证所指定item位于屏幕顶部,比如无法将处于屏幕中部的item滑动到屏幕顶部。那么一下提供下我解决的方法。
解决方法按照效果是否平滑分为两种:(至于平滑和非平滑的效果的不同,类比下面效果图便知道)
第一种:非平滑效果的实现方式
private void moveToPosition(int position) {
if (position != -1) {
mRecyclerView.scrollToPosition(position);
LinearLayoutManager mLayoutManager =
(LinearLayoutManager) mRecyclerView.getLayoutManager();
mLayoutManager.scrollToPositionWithOffset(position, 0);
}
}
实现效果:
第二种:平滑效果的实现方式
首先获取第一个可见位置和最后一个可见位置,分三种情况:
1.如果如果跳转位置在第一个可见位置之前,就smoothScrollToPosition()可以直接跳转;
2.如果跳转位置在第一个可见项之后,最后一个可见项之前smoothScrollToPosition()不会滚动,此时调用smoothScrollBy来滑动到指定位置;
3.如果要跳转的位置在最后可见项之后,则先调用smoothScrollToPosition()将要跳转的位置滚动到可见位置,在addOnScrollListener()里通过onScrollStateChanged控制,调用smoothMoveToPosition,再次执行判断;
//目标项是否在最后一个可见项之后
private boolean mShouldScroll;
//记录目标项位置
private int mToPosition;
/**
* 使指定的项平滑到顶部
*
* @param mRecyclerView
* @param position 待指定的项
*/
private void smoothMoveToPosition(RecyclerView mRecyclerView, final int position) {
int firstItemPosition = -1;
int lastItemPosition = -1;
//todo 获取第一个和最后一个可见位置方式1
// 第一个可见位置
firstItemPosition = mRecyclerView.getChildLayoutPosition(mRecyclerView.getChildAt(0));
// 最后一个可见位置
lastItemPosition = mRecyclerView.getChildLayoutPosition(mRecyclerView.getChildAt(mRecyclerView.getChildCount() - 1));
//todo 获取第一个和最后一个可见位置方式2
// 判断是当前layoutManager是否为LinearLayoutManager
// 只有LinearLayoutManager才有查找第一个和最后一个可见view位置的方法
// RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager();
// if (layoutManager instanceof LinearLayoutManager) {
// LinearLayoutManager linearManager = (LinearLayoutManager) layoutManager;
// //获取第一个可见view的位置
// firstItemPosition = linearManager.findFirstVisibleItemPosition();
// //获取最后一个可见view的位置
// lastItemPosition = linearManager.findLastVisibleItemPosition();
//
// }
Log.i(TAG, "smoothMoveToPosition: firstItemPosition::" + firstItemPosition + " lastItemPosition::" + lastItemPosition + "\n");
if (position < firstItemPosition) {
// 第一种可能:跳转位置在第一个可见位置之前
mRecyclerView.smoothScrollToPosition(position);
} else if (position <= lastItemPosition) {
// 第二种可能:跳转位置在第一个可见位置之后,在最后一个可见项之前
int movePosition = position - firstItemPosition;
if (movePosition >= 0 && movePosition < mRecyclerView.getChildCount()) {
int top = mRecyclerView.getChildAt(movePosition).getTop();
mRecyclerView.smoothScrollBy(0, top);//dx>0===>向左 dy>0====>向上
}
} else {
// 第三种可能:跳转位置在最后可见项之后
mRecyclerView.smoothScrollToPosition(position);
mToPosition = position;
mShouldScroll = true;
}
}
其中用于获取RecyclerView的第一个和最后一个可见项的方式有两种,上述代码中已经贴出来了。顺便在贴一遍
//方式1:
// 第一个可见位置
firstItemPosition = mRecyclerView.getChildLayoutPosition(mRecyclerView.getChildAt(0));
// 最后一个可见位置
lastItemPosition = mRecyclerView.getChildLayoutPosition(mRecyclerView.getChildAt(mRecyclerView.getChildCount() - 1));
//方式2
// 判断是当前layoutManager是否为LinearLayoutManager
// 只有LinearLayoutManager才有查找第一个和最后一个可见view位置的方法
RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager();
if (layoutManager instanceof LinearLayoutManager) {
LinearLayoutManager linearManager = (LinearLayoutManager) layoutManager;
//获取第一个可见view的位置
firstItemPosition = linearManager.findFirstVisibleItemPosition();
//获取最后一个可见view的位置
lastItemPosition = linearManager.findLastVisibleItemPosition();
}
其中,针对第三种情况——跳转的位置在最后可见项之后的情况,还需要添加如下代码:
//监听事件的设置,仅仅是为了第三种情况,即:要跳转的位置在可见项之后
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (mShouldScroll && RecyclerView.SCROLL_STATE_IDLE == newState) {//
mShouldScroll = false;
smoothMoveToPosition(mRecyclerView, mToPosition);
}
}
});
实现效果:
至此完结,小伙伴,如有问题请留言。