Reproduced at https://github.com/baiiu
When using RecyclerView, the smoothScrollToPostion() method is called to slide to the specified location, but entries often slide very slowly. This article is to realize the fast sliding of RecyclerView.
This paper first introduces how to implement it, then introduces the principle.
1. Implementation code
- Create FastScrollLinear Layout Manager, inherit Linear Layout Manager
- Override the smoothScrollToPosition() method, mainly the method in LinearSmoothScroller
The code is as follows. Explanations are all in the comments.
public class FastScrollLinearLayoutManager extends LinearLayoutManager {
public FastScrollLinearLayoutManager(Context context) {
super(context);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return FastScrollLinearLayoutManager.this.computeScrollVectorForPosition(targetPosition);
}
//This method controls the speed.
//if returned value is 2 ms, it means scrolling 1000 pixels with LinearInterpolation should take 2 seconds.
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
/*
Control unit speed, milliseconds/pixels, how many milliseconds does it take to slide one pixel?
Default is (25F/densityDpi) ms/pixels
mdpi On the top, there are 160 pixels in an inch, 25/160.
xxhdpi,1 The inch has 480 pixels, 25/480.
*/
//return 10F / displayMetrics.densityDpi; // Can reduce time, default 25F
return super.calculateSpeedPerPixel(displayMetrics);
}
//This method calculates the sliding time. Indirectly control the speed here.
//Calculates the time it should take to scroll the given distance (in pixels)
@Override
protected int calculateTimeForScrolling(int dx) {
/*
Control the distance and then calculate the time according to the speed provided by the calculateSpeedPerPixel()).
By default, a scroll TARGET_SEEK_SCROLL_DISTANCE_PX = 10000 pixels.
This value can be reduced here to reduce the rolling time.
*/
//Increase speed in indirect computing or directly in calculateSpeedPerPixel
if (dx > 3000) {
dx = 3000;
}
int time = super.calculateTimeForScrolling(dx);
LogUtil.d(time);//Look at the printing time
return time;
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
From the two methods of duplication, we can see that both of them are to improve the sliding speed. One is to modify the speed directly, the other is to reduce the time needed by reducing the distance and indirectly improve the sliding speed.
Either way, you can see what you need. Next, I will talk about the principle of implementation. I'm just going to sort out the general process, but by now you've been able to achieve fast sliding.
2. RecyclerView sliding process combing
1. Call RecyclerView.smoothScrollToPosition(position)
public void smoothScrollToPosition(int position) {
//... directly invoked the method of LayoutManager
mLayout.smoothScrollToPosition(this, mState, position);
}
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
2. Linear Layout Manager
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
int position) {
LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
//...
};
//Setting the Endpoint Position
linearSmoothScroller.setTargetPosition(position);
//startSmoothScroll() is the method in LayoutManager.
startSmoothScroll(linearSmoothScroller);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
3. In Layout Manager
public void startSmoothScroll(SmoothScroller smoothScroller) {
//...
mSmoothScroller = smoothScroller;
//Call the SmoothScroller.start() method to start scrolling. this parameter refers to the current LayoutManager
mSmoothScroller.start(mRecyclerView, this);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
4. In SmoothScroller
void start(RecyclerView recyclerView, LayoutManager layoutManager) {
//...
//Using ViewFlinger for animation, ViewFlinger implements the Runnable interface and uses Scroller internally so that it can post itself and then continuously lay out Recycler View to achieve sliding.
mRecyclerView.mViewFlinger.postOnAnimation();
}
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
5. In ViewFlinger, this is the focus of sliding, omitting a lot of code logic
private class ViewFlinger implements Runnable {
@Override
public void run() {
if (scroller.computeScrollOffset()) {
//Calling SmoothScroller's onAnimation method
smoothScroller.onAnimation(dx - overscrollX, dy - overscrollY);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
6. In SmoothScroller
private void onAnimation(int dx, int dy) {
//...
if (mTargetView != null) {
// verify target position
if (getChildPosition(mTargetView) == mTargetPosition) {
//The position to slide to is displayed on the screen. In onTargetFound() method, the update differentiator is changed from a linear differentiator to a decelerating differentiator.
onTargetFound(mTargetView, recyclerView.mState, mRecyclingAction);
mRecyclingAction.runIfNecessary(recyclerView);
}
//...
if (mRunning) {
//Next slide
onSeekTargetStep(dx, dy, recyclerView.mState, mRecyclingAction);
//Calling the runIfNecessary method of the inner class Action
mRecyclingAction.runIfNecessary(recyclerView);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
7.Action medium
private void runIfNecessary(RecyclerView recyclerView) {
//The ViewFlinger.smoothScrollBy() method is called and passed into mDuration. mDuration is passed in when upDate() is in SmoothScroller, which is determined by the two methods mentioned above.
recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy, mDuration, mInterpolator);
}
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
8. Start scrolling in ViewFlinger
public void smoothScrollBy(int dx, int dy, int duration, Interpolator interpolator) {
if (mInterpolator != interpolator) {
mInterpolator = interpolator;
mScroller = ScrollerCompat.create(getContext(), interpolator);
}
setScrollState(SCROLL_STATE_SETTLING);
mLastFlingX = mLastFlingY = 0;
//Call Scroller to start scrolling, where duration is
mScroller.startScroll(0, 0, dx, dy, duration);
postOnAnimation();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
This section roughly describes the rolling process according to the process, involving more classes, and finally scrolls through Scroller.
Using Demo
public class FastScrollFragment extends Fragment implements View.OnClickListener {
private RecyclerView recyclerView;
private SimpleTextAdapter mAdapter;
private int mVisibleCount;
@Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_fastscroll, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
LinearLayoutManager linearLayoutManager = new FastScrollLinearLayoutManager(getContext());
recyclerView.setLayoutManager(linearLayoutManager);
mAdapter = new SimpleTextAdapter(getContext(), 500);
recyclerView.setAdapter(mAdapter);
recyclerView.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override public void onGlobalLayout() {
recyclerView.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
mVisibleCount = linearLayoutManager.findLastVisibleItemPosition()
- linearLayoutManager.findFirstVisibleItemPosition() + 1;
LogUtil.d("Display so many: +mVisibleCount);
}
});
recyclerView.addItemDecoration(
new RecyclerViewDivider(getContext(), LinearLayoutManager.VERTICAL, 20, Color.BLUE));
view.findViewById(R.id.fast_top)
.setOnClickListener(this);
view.findViewById(R.id.fast_top_zhihuway)
.setOnClickListener(this);
view.findViewById(R.id.fast_end)
.setOnClickListener(this);
return view;
}
@Override public void onClick(View v) {
switch (v.getId()) {
case R.id.fast_top_zhihuway:
/*
Similarly, first go directly to a position, then slide to the top.
*/
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
if (firstVisibleItemPosition > mVisibleCount) {
recyclerView.scrollToPosition(mVisibleCount);
}
recyclerView.smoothScrollToPosition(0);
break;
/*
Both of them shorten the unit time distance in Linear Smooth Scroller to reduce time and slide quickly.
*/
case R.id.fast_top:
recyclerView.smoothScrollToPosition(10000);
break;
case R.id.fast_end:
recyclerView.smoothScrollToPosition(0);
break;
}
}
}
Conclusion:
This article implements a fast scroll of RecyclerView, but one thing to note is that if your Item is complex, scrolling can get stuck. This is mentioned in a comment when looking at the source code, which was later found in practice. Have to say WeChat The circle of friends slides really fast. It uses ListView, which seems to open the FastEnable property.
Similarly, you can use RecyclerView.scrollToPosition(position) to slide directly to a certain position before using smoothScrollToPosition(0) to slide to the top. This is mentioned in the comment on jumpTo() in the Action class in RecyclerView. If you are far away, you can go to a location first and then slide.
Both ways of sliding to the top implements a small Demo. test The code is on GitHub. FastScrollFragment .
In addition, it is also used in small projects written by myself. ZhihuDaily You can see these two Demo s for more details.
Original address: http://blog.csdn.net/u014099894/article/details/51855129