Android 中水平自动滚动列表实现

水平滚动的思路借鉴于 Android RecyclerView打造自动循环效果,但是这个不能实现循环左右移动,所以我进行了一个小修改,添加了方向这个概念,并在滚动到最顶端的时候自动改变了方向。

水平自动滚动广告效果演示 水平自动滚动广告效果演示

1
2
3
4
5
if(recyclerView.canScrollHorizontally(scrollDirection)){
    recyclerView.scrollBy(2 * scrollDirection, 2 * scrollDirection);
}else{  //改变方向
    scrollDirection = -scrollDirection;
}

首先我们考虑到水平列表可以使用 RecycleView 实现:

1
2
mRecycleView.setLayoutManager(new LinearLayoutManager(this.getContext(),
        LinearLayoutManager.HORIZONTAL, false));

然后我们重写一下 RecycleView 继承并使用 scrollBy() 方法来实现自动滚动。

 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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/**
 * 描述:
 * 日期:2019/12/23
 * 作者:水寒
 * 邮箱:lxq_xsyu@163.com
 */
public class AutoPollRecyclerView extends RecyclerView {

    private static final long TIME_AUTO_POLL = 16;
    AutoPollTask autoPollTask;

    private boolean running; //标示是否正在自动轮询
    private boolean canRun;//标示是否可以自动轮询,可在不需要的是否置false

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

    static class AutoPollTask implements Runnable {

        private int scrollDirection = 1; //默认向左移动
        private final WeakReference<AutoPollRecyclerView> mReference;

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

        @Override
        public void run() {
            AutoPollRecyclerView recyclerView = mReference.get();
            if (recyclerView != null && recyclerView.running &&recyclerView.canRun) {
                if(recyclerView.canScrollHorizontally(scrollDirection)){
                    recyclerView.scrollBy(2 * scrollDirection, 2 * scrollDirection);
                }else{  //改变方向
                    scrollDirection = -scrollDirection;
                }
                recyclerView.postDelayed(recyclerView.autoPollTask,recyclerView.TIME_AUTO_POLL);
            }
        }
    }

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

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

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        switch (e.getAction()){
            case MotionEvent.ACTION_DOWN:
                if (running)
                    stop();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_OUTSIDE:
                if (canRun)
                    start();
                break;
        }
        return super.onTouchEvent(e);
    }
}

这样便可以实现一个水平自动滚动的广告列表,接下来我们只需要在需要的地方调用 start() 方法启动:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
//绑定 adapter
mAdapter = new HomeScrollGoodsListAdapter();
mRecycleView.setAdapter(mAdapter);

//测试数据
for(int i = 0; i < 10; i++){
    GoodsBean goodsBean = new GoodsBean();
    goodsBean.device_goods_id = (i + 1);
    mGoodsItems.add(goodsBean);
}
mAdapter.setNewData(mGoodsItems);

//判断当大于某个数量后才启动滚动(滚动的前提是大于屏幕宽度)
if(mGoodsItems.size() >= SCROLL_MIN_COUNT){
    mRecycleView.start();
}