Android 自动滚动的RecyclerView,手动滑动和自动滑动无缝衔接,手动滑动时数据不重复

时间:2025-01-31 11:41:26

概要

做一个自动滑动的列表,用于展示聊天记录或者通知栏信息等,还是使用主流的RecyclerView来做。网上有很多案例,但当手动滑动时会一直无限循环,数据重复的出现,如果想要自动滑动时能无限循环,手动滑动时又能滑到底呢?本案例就解决这种手动滑动和自动滑动无缝衔接的问题。

思路

1、重写RecyclerView,通过scrollBy和postDelayed进行定时移动到达自动滑动目的

2、RecyclerView添加addOnScrollListener,进行手指按下滑动和抬起监听,用于判断是手动滑动还是自动滑动。

3、修改adapter的itemCount

4、接下来上代码

实现方案

1、重写 RecyclerView:

public class SocllRecyclerView extends RecyclerView {
    private Autoaaview autoview;
    private boolean running;
    private boolean canrun;

    private static final int Timea = 40;//控制滚动的速度,值越大速度越慢

    public SocllRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        autoview = new Autoaaview(this);
    }

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


    private class Autoaaview implements Runnable{
        WeakReference<SocllRecyclerView> myScrViewWeakReference;
        public Autoaaview(SocllRecyclerView myScrView) {
            myScrViewWeakReference = new WeakReference<>(myScrView);
        }

        @Override
        public void run() {
            SocllRecyclerView myScrView = ();
            if (&&){
                (2,2);
                (,Timea);
            }
        }
    }
    //开始滚动
    public void start(){
        if (running)
            stop();
        running = true;
        canrun = true;
        postDelayed(autoview,Timea);
    }
    //停止滚动
    public void stop() {
        running = false;
        removeCallbacks(autoview);
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        return (e);
    }
}

2、适配器 MyscrviewAdapter

public class MyscrviewAdapter extends <ViewHolder> {

    Context context;
    List<> mies;
    private int itemCount = Integer.MAX_VALUE;

    public MyscrviewAdapter(Context context, List<> mies) {
         = context;
         = mies;
    }

    public void updateAll(List<> list) {
        ();
        (list);
        notifyDataSetChanged();
    }

    /**
     * 设置状态,用于设置ItemCount的数量
     * state:1 表示正在手指滑动,itemCount设置为实际数量;
     * 其他的表示结束手动滑动,itemCount设置为最大值Integer.MAX_VALUE
     * @param state
     */
    public void setItemCount(int state) {
         = state == 1 ? () : Integer.MAX_VALUE;
        notifyDataSetChanged();
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View inflate = (context).inflate(.item_home_news, parent, false);
        ViewHolder baseViewHolder = new ViewHolder(inflate);
        return baseViewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
        (, (position % ()).getTitle());
        (new () {
            @Override
            public void onClick(View v) {
                if (null != mItemClickListener) {
                    ((position % ()), position);
                }
            }
        });
    }

    @Override
    public int getItemCount() {
        return () > 4 ? itemCount : ();
    }

    //使用接口回调点击事件
    private ItemClickListener mItemClickListener;

    public void setOnItemClickListener(ItemClickListener itemClickListener) {
         = itemClickListener;
    }
    
    public interface ItemClickListener {
        void onItemClick(Object obj, int position);
    }
}

ViewHolder封装类

public class ViewHolder extends  {
    //用于缓存已找的界面
    private SparseArray<View> mView;

    public ViewHolder(View itemView) {
        super(itemView);
        mView=new SparseArray<>();
    }
    public <T extends View> T getView(int viewId){
        //对已有的view做缓存
        View view=(viewId);
        //使用缓存的方式减少findViewById的次数
        if(view==null){
            view=(viewId);
            (viewId,view);
        }
        return (T) view;
    }
    //通用的功能进行封装  设置文本 设置条目点击事件  设置图片
    public ViewHolder setText(int viewId , CharSequence text){
        TextView view = getView(viewId);
        (text);
        //希望可以链式调用
        return this;
    }

    //通用的功能进行封装  设置文本 设置条目点击事件  设置图片
    public ViewHolder setText(int viewId , String text){
        TextView view = getView(viewId);
        (text);
        //希望可以链式调用
        return this;
    }

    public ViewHolder setSelected(int viewId ,boolean selected){
        TextView view = getView(viewId);
        (selected);
        //希望可以链式调用
        return this;
    }

    public ViewHolder setSelected2(int viewId,boolean selected){
        View view = getView(viewId);
        (selected);
        return this;
    }

    public ViewHolder setVisible(int viewId,boolean visible){
        View view = getView(viewId);
        (visible ?  : );
        return this;
    }

    public ViewHolder setVisible(int viewId,boolean visible,boolean isLocation){
        View view = getView(viewId);
        if (isLocation){
            (visible ?  : );
        }else{
            (visible ?  : );
        }

        return this;
    }

    /**
     *设置本地图片
     * @param viewId
     * @param resId
     * @return
     */
    public ViewHolder setImageResource(int viewId,int resId){
        ImageView iv=getView(viewId);
        (resId);
        return this;
    }

    public ViewHolder setTextSelected(int viewId, boolean bool) {
        TextView tv = getView(viewId);
        (bool);
        return this;
    }

    /**
     *设置本地图片
     * @param viewId
     * @param resId
     * @return
     */
    public ViewHolder setImageDrawable(Context mContext, int viewId, int resId){
        ImageView iv=getView(viewId);
        (().getDrawable(resId));
        return this;
    }

    /**
     * 加载图片资源路径
     * @param viewId
     * @param imageLoader
     * @return
     */
    public ViewHolder setImagePath(int viewId,HolderImageLoader imageLoader,int res){
        ImageView iv=getView(viewId);
        (iv,(),res);
        return this;
    }

    public ViewHolder setImage(Context mContext, int viewId, String url, int res) {
        ImageView view = getView(viewId);
        (mContext, view, url,res);
        return this;
    }

    public ViewHolder setCircleImage(Context mContext, int viewId, String url, int res) {
        ImageView view = getView(viewId);
        (mContext, view, url,res);
        return this;
    }

    public ViewHolder setTextColor(Context mContext, int viewId, int color) {
        TextView tv = (TextView)(viewId);
        (().getColor(color));
        return this;
    }

    public ViewHolder setTextSize(Context mContext, int viewId, float res) {
        TextView tv = (TextView)(viewId);
        (Utils.dp2px(mContext,res));
        return this;
    }

    @SuppressLint("NewApi")
    public ViewHolder setBackground(Context mContext, int viewId, int bg) {
        TextView tv = (TextView)(viewId);
        (().getDrawable(bg));
        return this;
    }

    /**
     * 关于事件的
     */
    public ViewHolder setOnClickListener(int viewId,  listener) {
        View view = getView(viewId);
        (listener);
        return this;
    }

    public abstract static class HolderImageLoader{
        public String mPath;
        public Context mContext;
        public HolderImageLoader(Context mContext, String path){
            =path;
             = mContext;
        }

        /**
         * 需要去复写这个方法加载图片
         * @param iv
         * @param path
         */
        public abstract void loadImage(ImageView iv, String path, int res);
        public String getPath(){
            return mPath;
        }
    }

}

3、activity中使用

     RecyclerView滑动监听,注释都说的很详细

/**
     * 控制通知公告数据滚动
     * 手指滑动时 停止自动滚动
     * 手指抬起时,3秒后自动开始滚动
     */
    private void initRlvNews() {
        scroHandler = new Handler();//定义handler
        runnable = () -> {  //runnable方法,处理延时后的操作
            (0);//0表示手指已经抬起来了
            (); //开始滑动
        };
        (new () {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                (recyclerView, newState);
                if (null != newsAdapter) {
                    if (newState == 1) {//newState的值:1 手指按下拖拽滚动,2自动滚动(一般指惯性滚动),0 禁止没有滚动
                        ();//停止自动滚动
                        (newState);
                    } else {
                        (runnable);//清除runnable重新开始
                        //这里设置3秒是预估了手指滑动抬起再滑动的时间,提升体验
                        (runnable, 3000);
                    }
                }
            }
        });
    }

4、布局文件:

  需要给固定高度

<
 android:
 android:layout_width="match_parent"
 android:layout_height="144dp"/>

5、数据绑定

         ()//可设置水平滚动或竖直滚动布局

        MyscrviewAdapter adpter=new MyscrviewAdapter(this,list)

        (adpter)

        //关键,条件自定义,如当列表数据大于4条时开始滑动

        if(()>4){

                (); //开始滑动

        }

结束------------