展开说说:Android列表之RecyclerView

RecyclerView 它是从Android5.0出现的全新列表组件,更加强大和灵活。用于显示列表形式 (list) 或者网格形式 (grid) 的数据,替代ListView和GridView成为Android主流的列表组件。可以说Android客户端只要有表格的地方就有RecyclerView。

RecyclerView 内置 ViewHolder ,省去了每次 findViewById() 创建视图;当列表滑动的时候,只有少量相邻的视图会被创建。当视图滑出屏幕时,RecyclerView 会复用它并且填充新的数据。由于它是通过回收已有的结构而不是持续创建新的列表项,所以它可以有效提高应用的时间效率和空间效率。

RecyclerView 拥有三种 LayoutManager,LinearLayoutManager

它支持纵向滑动的列表和横向滑动的列表;GridLayoutManager

实现网格布局的列表;StaggeredGridLayoutManager

实现瀑布流布局。并且支持自定义 LayoutManager;

RecyclerView 还可以定制一些动画增加趣味性。

稍微繁琐的一点是RecyclerView没有直接提供点击和长按事件处理方法,没有提供ItemClickListener和ItemLongClickListener,因此我们可以给某个控件加点击事件然后自己通过一个接口回调放到Activity'或者Fragment中来处理事件,个人认为这样方便操作数据源。

上面提到它是在v7包,所以一定不要忘了导包哈。

RecyclerView功能强大,本篇文章先记录横竖方向的线性列表和网格布局,瀑布流使用与这两者相似请自行实验;列表滑动、点击事件更新列表以及线程切换更新等。

  1. build.gradle引用RecyclerView

使用support.V7 包的需要导包,androidx包的不用单独引用

2. xml文件声明

java 复制代码
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerAct_recycler"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
  1. findViewById并使用

recycler = findViewById(R.id.recyclerAct_recycler );

  1. 设置LayoutManager
java 复制代码
4.1竖向布局
if (linearLayoutManager == null){
    linearLayoutManager = new LinearLayoutManager(RecyclerViewActivity.this);
}
recycler.setLayoutManager(linearLayoutManager);
此处可以设置横向,默认是竖向
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
4.2网格布局
if (gridLayoutManager == null){
    gridLayoutManager = new GridLayoutManager(RecyclerViewActivity.this, 3);
}
recycler.setLayoutManager(gridLayoutManager);

瀑布流布局StaggeredGridLayoutManager可自行试验

5.定义Adapter继承RecyclerView.Adapter

通过源码可以看出Adapter是RecyclerView的一个内部类,他还是个抽象类,内部onCreateViewHolder、onBindViewHolder、getItemCount三个从抽象方法,我们实现的子类必须重写,分别是创建布局、渲染数据、数据源数量。

通过源码可以看出Adapter是RecyclerView的一个内部类,他还是个抽象类,但无抽象方法。

还定义了changeData这个方法,如果修改了数据源可以调用它来进行刷新:

java 复制代码
public void changeData(List<String> data){
    mData.clear();
    mData.addAll(data);
    notifyDataSetChanged();
}

6. setAdapter并传递数据进行展示

adapter = new GridLayoutAdapter(this);
recycler.setAdapter(adapter);

7.点击事件处理

没有提供ItemClickListener和ItemLongClickListener,因此我们可以给某个控件加点击事件然后自己通过一个接口回调放到Activity'或者Fragment中来处理事件,我个人认为这样方便操作源数据。

定义接口:

java 复制代码
public void setItemClickListener(OnItemClickListener itemClickListener){
    mItemClickListener = itemClickListener;
}


public interface OnItemClickListener {
    void onItemClick(int positon);
}

点击事件:

java 复制代码
@Override
public void onBindViewHolder(@NonNull GridLayoutAdapter.ViewHolder holder, int position) {
    holder1.name.setText(mData.get(position));
    holder1.name.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            mItemClickListener.onItemClick(position);
            selectPosition = position;
        }
    });

}

7.1​​​​​​​ 列表竖向和表格切换,仿电商App

java 复制代码
 changeTV.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (adapter == null){
                    adapter = new GridLayoutAdapter(RecyclerViewActivity.this);
                }
                if ("竖向".equals(changeTV.getText().toString().trim())){
                    if (gridLayoutManager == null){
                        gridLayoutManager = new GridLayoutManager(RecyclerViewActivity.this, 3);
                    }
                    recycler.setLayoutManager(gridLayoutManager);
                    changeTV.setText("网格");
                }else {
                    if (linearLayoutManager == null){
                        linearLayoutManager = new LinearLayoutManager(RecyclerViewActivity.this);
                    }
//                    linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
                    recycler.setLayoutManager(linearLayoutManager);
                    changeTV.setText("竖向");
                }
                recycler.setAdapter(adapter);
                adapter.changeData(mDataList);
            }
        });

7.2 将列表滑到指定索引的item

recycler.smoothScrollToPosition(42);

滑动到制定索引的位置,是指的最下方漏出来哪一条。有滑动过渡的效果。所以超过item数据总和的总都会适配直接滑动最极限值(最后一条),不会报错

recycler.scrollBy(0,360);

滑动到制定宽高的位置,是指的最下方一条的位置。没有滑动过渡的效果。scrollBy相对初始位置每次移动这些距离,超过recycler的总高度或宽度都会适配直接滑动最极限值(总宽和总高),不会报错

recycler.scrollTo(0,-2260); 好坑啊

试了几个值,但都没有滑动,好坑啊,源码是个空壳打印了一行Warn级别的日志:2024-06-27 16:41:12.102 29806-29806/ 包名 W/RecyclerView: RecyclerView does not support scrolling to an absolute position. Use scrollToPosition instead,重写了父类View就是为了毁灭它吧,

addOnScrollListener可以监听recycler的滑动状态和滑动位置:

java 复制代码
recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        Log.e(TAG, "onScrollStateChanged: newState= "+newState );
    }

    @Override
    public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        Log.e(TAG, "onScrolled: dx= "+dx+"    dy= "+dy );
    }
});

7.3 点击修改item背景

java 复制代码
    //设置item背景颜色
    if (selectPosition == position){
        holder1.name.setBackgroundColor(mActivity.getResources().getColor(R.color.red));
    }else {
        holder1.name.setBackgroundColor(mActivity.getResources().getColor(R.color.white));
    }

7.4 点击删除指定item

7.4.1** 直接这样 操作没有 没问题,但是 很生硬不死话**

mDataList.remove(positon);
adapter.changeData(mDataList);

7.4.2

使用API方法加一下删除动画

mDataList.remove(positon);

adapter.notifyItemRemoved(positon);

adapter.notifyChanged(positon,mDataList);

注意:notifyItemRemoved方法比较坑,调用notifyItemRemoved以后一定要再调用notifyItemRangeRemoved这个方法,并且要有设置给recycler的数据的直接变化,直白点就是getItemCount方法中标示长度的哪个数据源,修改最最源头源头的数据源二不改变这个是无效的

getItemCount方法是上面第5条提过的返回数据源数量。notifyChanged和面第5条提过changeData方法一样,不过吧notifyDataSetChanged();换成了notifyItemRangeRemoved(position,mData.size() - position);

java 复制代码
public void notifyChanged(int position,List<String> data){
    mData.clear();
    mData.addAll(data);
    //调用notifyItemRemoved以后一定要再调用这个方法,并且要有设置给recycler的数据的直接变化,直白点就是getItemCount中标示长度的哪个数据源,修改最最源头源头的数据源二不改变这个是无效的
    notifyItemRangeRemoved(position,mData.size() - position);
}

7.5 子线程切换到主线程更新UI

因为RecyclerView继承ViewGroup,而ViewGroup继承View,所以这里直接使用了爷类View的post方法。

recycler.post(new Runnable() {
@Override
public void run() {

可执行页面刷新操作

}
});

才疏学浅,如有错误,欢迎指正,多谢。

相关推荐
烬奇小云3 小时前
认识一下Unicorn
android·python·安全·系统安全
顾北川_野15 小时前
Android 进入浏览器下载应用,下载的是bin文件无法安装,应为apk文件
android
CYRUS STUDIO15 小时前
Android 下内联汇编,Android Studio 汇编开发
android·汇编·arm开发·android studio·arm
右手吉他15 小时前
Android ANR分析总结
android
PenguinLetsGo17 小时前
关于 Android15 GKI2407R40 导致梆梆加固软件崩溃
android·linux
杨武博19 小时前
音频格式转换
android·音视频
音视频牛哥21 小时前
Android音视频直播低延迟探究之:WLAN低延迟模式
android·音视频·实时音视频·大牛直播sdk·rtsp播放器·rtmp播放器·android rtmp
ChangYan.21 小时前
CondaError: Run ‘conda init‘ before ‘conda activate‘解决办法
android·conda
二流小码农21 小时前
鸿蒙开发:ForEach中为什么键值生成函数很重要
android·ios·harmonyos
夏非夏1 天前
Android 生成并加载PDF文件
android