Android 自动滚动的RecyclerView,手动滑动和自动滑动无缝衔接,手动滑动时数据不重复
概要
(图片来源网络,侵删)
做一个自动滑动的列表,用于展示聊天记录或者通知栏信息等,还是使用主流的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 myScrViewWeakReference; public Autoaaview(SocllRecyclerView myScrView) { myScrViewWeakReference = new WeakReference(myScrView); } @Override public void run() { SocllRecyclerView myScrView = myScrViewWeakReference.get(); if (myScrView.canrun&&myScrView.running){ myScrView.scrollBy(2,2); myScrView.postDelayed(myScrView.autoview,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 super.onTouchEvent(e); } }
2、适配器 MyscrviewAdapter
public class MyscrviewAdapter extends RecyclerView.Adapter { Context context; List mies; private int itemCount = Integer.MAX_VALUE; public MyscrviewAdapter(Context context, List mies) { this.context = context; this.mies = mies; } public void updateAll(List list) { mies.clear(); mies.addAll(list); notifyDataSetChanged(); } /** * 设置状态,用于设置ItemCount的数量 * state:1 表示正在手指滑动,itemCount设置为实际数量; * 其他的表示结束手动滑动,itemCount设置为最大值Integer.MAX_VALUE * @param state */ public void setItemCount(int state) { this.itemCount = state == 1 ? mies.size() : Integer.MAX_VALUE; notifyDataSetChanged(); } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View inflate = LayoutInflater.from(context).inflate(R.layout.item_home_news, parent, false); ViewHolder baseViewHolder = new ViewHolder(inflate); return baseViewHolder; } @Override public void onBindViewHolder(@NonNull ViewHolder holder, final int position) { holder.setText(R.id.tvNewsTitle, mies.get(position % mies.size()).getTitle()); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (null != mItemClickListener) { mItemClickListener.onItemClick(mies.get(position % mies.size()), position); } } }); } @Override public int getItemCount() { return mies.size() > 4 ? itemCount : mies.size(); } //使用接口回调点击事件 private ItemClickListener mItemClickListener; public void setOnItemClickListener(ItemClickListener itemClickListener) { this.mItemClickListener = itemClickListener; } public interface ItemClickListener { void onItemClick(Object obj, int position); } }
ViewHolder封装类
public class ViewHolder extends RecyclerView.ViewHolder { //用于缓存已找的界面 private SparseArray mView; public ViewHolder(View itemView) { super(itemView); mView=new SparseArray(); } public T getView(int viewId){ //对已有的view做缓存 View view=mView.get(viewId); //使用缓存的方式减少findViewById的次数 if(view==null){ view=itemView.findViewById(viewId); mView.put(viewId,view); } return (T) view; } //通用的功能进行封装 设置文本 设置条目点击事件 设置图片 public ViewHolder setText(int viewId , CharSequence text){ TextView view = getView(viewId); view.setText(text); //希望可以链式调用 return this; } //通用的功能进行封装 设置文本 设置条目点击事件 设置图片 public ViewHolder setText(int viewId , String text){ TextView view = getView(viewId); view.setText(text); //希望可以链式调用 return this; } public ViewHolder setSelected(int viewId ,boolean selected){ TextView view = getView(viewId); view.setSelected(selected); //希望可以链式调用 return this; } public ViewHolder setSelected2(int viewId,boolean selected){ View view = getView(viewId); view.setSelected(selected); return this; } public ViewHolder setVisible(int viewId,boolean visible){ View view = getView(viewId); view.setVisibility(visible ? View.VISIBLE : View.GONE); return this; } public ViewHolder setVisible(int viewId,boolean visible,boolean isLocation){ View view = getView(viewId); if (isLocation){ view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); }else{ view.setVisibility(visible ? View.VISIBLE : View.GONE); } return this; } /** *设置本地图片 * @param viewId * @param resId * @return */ public ViewHolder setImageResource(int viewId,int resId){ ImageView iv=getView(viewId); iv.setImageResource(resId); return this; } public ViewHolder setTextSelected(int viewId, boolean bool) { TextView tv = getView(viewId); tv.setSelected(bool); return this; } /** *设置本地图片 * @param viewId * @param resId * @return */ public ViewHolder setImageDrawable(Context mContext, int viewId, int resId){ ImageView iv=getView(viewId); iv.setImageDrawable(mContext.getResources().getDrawable(resId)); return this; } /** * 加载图片资源路径 * @param viewId * @param imageLoader * @return */ public ViewHolder setImagePath(int viewId,HolderImageLoader imageLoader,int res){ ImageView iv=getView(viewId); imageLoader.loadImage(iv,imageLoader.getPath(),res); return this; } public ViewHolder setImage(Context mContext, int viewId, String url, int res) { ImageView view = getView(viewId); GlideLoadImageUtils.loadRectangleImg(mContext, view, url,res); return this; } public ViewHolder setCircleImage(Context mContext, int viewId, String url, int res) { ImageView view = getView(viewId); GlideLoadImageUtils.loadCircleImg(mContext, view, url,res); return this; } public ViewHolder setTextColor(Context mContext, int viewId, int color) { TextView tv = (TextView)this.getView(viewId); tv.setTextColor(mContext.getResources().getColor(color)); return this; } public ViewHolder setTextSize(Context mContext, int viewId, float res) { TextView tv = (TextView)this.getView(viewId); tv.setTextSize(Utils.dp2px(mContext,res)); return this; } @SuppressLint("NewApi") public ViewHolder setBackground(Context mContext, int viewId, int bg) { TextView tv = (TextView)this.getView(viewId); tv.setBackground(mContext.getResources().getDrawable(bg)); return this; } /** * 关于事件的 */ public ViewHolder setOnClickListener(int viewId, View.OnClickListener listener) { View view = getView(viewId); view.setOnClickListener(listener); return this; } public abstract static class HolderImageLoader{ public String mPath; public Context mContext; public HolderImageLoader(Context mContext, String path){ this.mPath=path; this.mContext = 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方法,处理延时后的操作 newsAdapter.setItemCount(0);//0表示手指已经抬起来了 rlvNews.start(); //开始滑动 }; rlvNews.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (null != newsAdapter) { if (newState == 1) {//newState的值:1 手指按下拖拽滚动,2自动滚动(一般指惯性滚动),0 禁止没有滚动 rlvNews.stop();//停止自动滚动 newsAdapter.setItemCount(newState); } else { scroHandler.removeCallbacks(runnable);//清除runnable重新开始 //这里设置3秒是预估了手指滑动抬起再滑动的时间,提升体验 scroHandler.postDelayed(runnable, 3000); } } } }); }
4、布局文件:
需要给固定高度
5、数据绑定
rlvNews.setLayoutManager()//可设置水平滚动或竖直滚动布局
MyscrviewAdapter adpter=new MyscrviewAdapter(this,list)
rlvNews.setAdapter(adpter)
//关键,条件自定义,如当列表数据大于4条时开始滑动
if(list.size()>4){
rlvNews.start(); //开始滑动
}
结束------------
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。