安卓项目实战之:RecyclerView实现中奖公告列表信息垂直自动无限滚动效果

版权声明:转载必须注明本文转自郭子轩的博客 https://blog.csdn.net/gpf1320253667/article/details/85111090

效果图

在这里插入图片描述
录的屏滑动有点卡,其实还是很丝滑的。
(半夜三点钟还在写博客,只希望这个系列博客可以帮助到更多人,后期还会一直更新,欢迎大家评论点赞,你们的支持是我永远的动力,嘿嘿。)

实现的思路

通过调用RecyclerView的smoothScrollToPosition(int position)方法我们可以实现平滑的滚动到参数所指定的position的位置,如果仅仅是调用了该方法那么滚动将会以系统默认的速度来进行,并且该速度通常是非常快的,快到如果将参数position的值设置的很小可能会看不到滚动的过程而直接看到结果,设置稍微大点例如为100时就会看到2秒的滚动效果,值越大滚动过程持续的时间越长,并且执行该方法滚动到该位置之后会立刻停止滚动,我们本篇文章讲的是RecyclerView如何实现自动无限滚动效果,因此我们可以这么来实现:
1,设置RecyclerView的item数量为int类型的最大值,这样滚动过程就会持续很长时间,会给用户造成一种错觉是无限滚动,其实也是单次的,等到滚动到int最大值指定的那个位置就会停止,但是一般用户不可能等那么长时间,如果不放心我们也可以在代码中设置实现循环滚动,
2,解决滚动速度的问题,前面说了,系统默认的滚动速度是非常快的,可能一秒钟就滚动过了几十个item甚至接近一百个item,滚动太快致使item内容在滚动过程中完全看不清楚,显然我们需求肯定不是这样的,我们要实现item的缓慢自动滚动,并且在滚动过程中要能清楚的看到每个item的内容,那么我们就需要改变系统默认的滚动速度,做法是自定义一个LayoutManager类继承LinearLayoutManager,然后复写smoothScrollToPosition方法。在该方法中创建一个Scroller对象,在Scroller对象中再重写calculateSpeedPerPixel(DisplaMetrics)方法,该方法就是用来控制滚动速度的,具体请看下面代码示例。

1,布局文件很简单就是定义了一个RecyclerView,MainActivity代码如下:

public class MainActivity extends AppCompatActivity {

    AutoScrollRecyclerView recyclerView;
    private List<String> list = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = findViewById(R.id.recyclerView);

        for(int i=0;i<30;i++){
            list.add("我是条目"+i);
        }
        LinearLayoutManager manager = new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false);
//        AutoScrollLayoutManager manager = new AutoScrollLayoutManager(this,LinearLayoutManager.VERTICAL,false);
        recyclerView.setLayoutManager(manager);
        // 设置适配器
        Adapter mAdapter = new Adapter(this, list);
        recyclerView.setAdapter(mAdapter);
        // 调用该方法来触发自动滚动
        recyclerView.smoothScrollToPosition(mAdapter.getItemCount());

    }


    class Adapter extends RecyclerView.Adapter<MainActivity.ViewHolder> {

        private Context context;
        private List<String> list;

        public Adapter(Context context, List<String> list) {
            this.context = context;
            this.list = list;
        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_recycler, parent, false));
        }

        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            if(!list.isEmpty()){
                // 因为getItemCount返回int最大值,而我们设置的数据不可能那么多,所以在为item绑定数据的时候,我们
                // 这里采用取余的方法,这样就能保证每一项item都是有值的,但为了不重复就要求我们的样本数据多一点
                holder.vText.setText(list.get(position%list.size()));
            }
        }

        @Override
        public int getItemCount() {
            // 返回int最大值
            return list == null ? 0 : Integer.MAX_VALUE;
        }
    }

    class ViewHolder extends RecyclerView.ViewHolder {
        TextView vText;
        public ViewHolder(View itemView) {
            super(itemView);
            vText = itemView.findViewById(R.id.tv);
        }
    }

}

注意上面getItemCount和onBindViewHolder方法在定义时的小技巧,上面注释也已经写的很清楚了。

运行程序会发现此时自动滚动已经实现了,但是滚动速度还没处理,还是系统默认的,所以非常快,几乎看不到条目内容,接下来我们来处理滚动的速度,方法如下:

自定义一个类AutoScrollLayoutManager继承LinearLayoutManager,然后复写smoothScrollToPosition方法。在该方法中创建一个Scroller对象,在Scroller对象中再重写calculateSpeedPerPixel(DisplaMetrics)方法,代码如下:

public class AutoScrollLayoutManager extends LinearLayoutManager {

    public AutoScrollLayoutManager(Context context) {
        super(context);
    }

    public AutoScrollLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    public AutoScrollLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    //  修改系统默认的滚动速度需要实现该方法;
    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int
            position) {
        LinearSmoothScroller linearSmoothScroller =
                new LinearSmoothScroller(recyclerView.getContext()) {
                    @Nullable
                    @Override
                    public PointF computeScrollVectorForPosition(int targetPosition) {
                        return AutoScrollLayoutManager.this.computeScrollVectorForPosition
                                (targetPosition);
                    }

                    @Override
                    protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
                        // 计算滑动每个像素需要的时间,这里应该与屏幕适配;
                        return 15f / displayMetrics.density;
                    }
                };
        linearSmoothScroller.setTargetPosition(position);
        startSmoothScroll(linearSmoothScroller);
    }

}

然后在创建布局管理器时,使用我们自定义的AutoScrollLayoutManager,此时再运行应用我们会发现现在速度已经慢了好多了,条目内容也可以看得清楚了。

但是还有个问题就是当RecyclerView在自动滚动过程中当我们用手触摸到了,它就会立刻停止滚动,并且它还能响应我们的滑动事件,而大多数时候需求仅仅是自动滚动展示数据而已,要求屏蔽我们的触摸和滑动动作,那么此时我们就需要自定义RecyclerView,重写两个与事件相关的方法,代码如下示例:

public class AutoScrollRecyclerView extends RecyclerView {

    public AutoScrollRecyclerView(Context context) {
        super(context);
    }

    public AutoScrollRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public AutoScrollRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    // 拦截事件;
    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        // 拦截触摸事件;
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        // 消费事件;
        return true;
    }

}

至此再运行代码,效果基本上已经能够满足需求了,前面也分析过看似无限滑动其实也只是一种错觉,是我们将条目总数设置的很大(int的最大值)将滚动速度设置的很小给用户造成的错觉,其实本质还是单次滚动,滚动到int最大值的位置还是会停止,为了实现真正意义上的无限滚动,我们可以通过监听RecyclerView的滑动状态来实现循环滚动,即当滚动到最后一个item时,再次重新定位到开始位置,然后再次滑动到最后一个item,依次循环,代码如下例:

this.setOnScrollListener(new OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
 
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    // 如果自动滑动到最后一个位置,则此处状态为SCROLL_STATE_IDLE
                    AutoScrollLayoutManager lm = (AutoScrollLayoutManager) recyclerView
                            .getLayoutManager();
 
                    int position = lm.findLastCompletelyVisibleItemPosition();
                    int count = lm.getItemCount();
                    if(position == count-1){
                        lm.scrollToPosition(0);
                        AutoScrollRecyclerView.this.smoothScrollToPosition(mAdapter.getItemCount());
                    }
                }
            }
        });

至此就实现了列表自动无限滚动效果。

猜你喜欢

转载自blog.csdn.net/gpf1320253667/article/details/85111090
今日推荐