循环滚动RecyclerView的实现

由于RecyclerView不支持自动滚动,那么首先我们需要进行一些自定义操作。
让RecyclerView自动滚动有两种思路。
方法1:添加属性动画,每次动画回调监听滚动1PX
方法2:使用postDelayed每隔一段时间发送一条消息,滚动RecyclerView。
经过试验验证,二者优劣如下表格所示:

方法 优缺点
1 1.实现简单,只需要一个属性动画即可
2.动画的回调间隔无法控制,会存在动画一直在回调。同时根据手机处理的动画的速度,会出现时快时慢的现象。
3.在动画回调中直接调用recyclerView.scrollBy(1,0)存在无法滚动的问题(原因暂未探查)
1 1.由于上述3的问题,所以直接通过postDelayed进行循环滚动的实现成了最主要原因。
2.能够大体控制时间的间隔

确定技术方案,编码实现如下:

public class AutoRecyclerView extends RecyclerView {
    
    

    private static final long TIME_AUTO_POLL = 16;
 	private final AutoPollTask autoPollTask;
	 private boolean running; //表示是否正在自动轮询
 	private boolean canRun;//表示是否可以自动轮询

 	public AutoRecyclerView(@NonNull Context context) {
    
    
        super(context);
 		autoPollTask = new AutoPollTask(this);
 	}

    public AutoRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
    
    
        super(context, attrs);
 		autoPollTask = new AutoPollTask(this);
 	}

    public AutoRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    
    
        super(context, attrs, defStyleAttr);
 		autoPollTask = new AutoPollTask(this);
 	}

    private static class AutoPollTask implements Runnable {
    
    
        private final WeakReference<AutoRecyclerView> mReference;

 	//使用弱引用持有外部类引用->防止内存泄漏
 	public AutoPollTask(AutoRecyclerView reference) {
    
    
            this.mReference = new WeakReference<>(reference);
 	}

        @Override
 	public void run() {
    
    
        AutoRecyclerView recyclerView = mReference.get();
 		if (recyclerView != null && recyclerView.running && recyclerView.canRun) {
    
    
 			//水平移动
            recyclerView.scrollBy(2, 0);
            //竖直移动
            //recyclerView.scrollBy(0, 2);
 			recyclerView.postOnAnimationDelayed(recyclerView.autoPollTask, TIME_AUTO_POLL);
 			}
        }
    }

    //开启:如果正在运行,先停止->再开启
 	private void start() {
    
    
        if (running)
            stop();
 		canRun = true;
 		running = true;
 		postDelayed(autoPollTask, TIME_AUTO_POLL);
 	}

    private void stop() {
    
    
        running = false;
 		removeCallbacks(autoPollTask);
 	}

    @Override
 	public boolean dispatchTouchEvent(MotionEvent ev) {
    
    
        return true;
 	}

    public void startAutoScrolling(){
    
    
        if (running){
    
    
            return;
		 }
        start();
 	}

    public void stopAutoScrolling(){
    
    
        stop();
 	}

    public boolean isAutoScrolling(){
    
    
        return running;
 	}
}

注:
1.时间间隔控制在16,是由于想保证一秒60帧的刷新率。保证每一帧都在运动。
2.最终编码采用的postOnAnimationDelayed而不是postDelayed主要是因为,postOnAnimationDelayed能够最大限度的保证动画的每一帧的执行。

附:
View.post 与View.postOnAnimation 有什么区别?
答:
view.post() 正常的向 Looper 中加入一条 Msg,遵守 Handler 消息执行逻辑。
view.postOnAnimation,向 Choreographer 中添加 CALLBACK_ANIMATION 类型的回调,该回调会在Choreographer 的一条异步消息中执行,在 VSYNC 信号到来时即会执行,即下一帧绘制之前就会执行,而 view.post() 提交的消息要比view.postOnAnimation延后一点执行。
简单一句话概述:post()会将runnable对象放在队列中等待执行。 postOnAnimation()方法会在下一帧立即执行runnable对象

猜你喜欢

转载自blog.csdn.net/tao_789456/article/details/127520949