AndroidStudio-3.2.1(十)RecyclerView

本篇介绍列表视图中RecyclerView的用法。

RecyclerView用来展现各种列表视图,它不仅是ListView的升级,之前的Gallery、GridView的效果它也都可以实现。下面通过一个示例来展示RecyclerView的用法。

  • 基本设置
  • 不同布局样式
  • 添加分割线
  • 点击事件
  • 下拉刷新

基本设置

先看最终实现的界面效果:
AndroidStudio-3.2.1(十)RecyclerView_第1张图片
1、首先添加一个Activity,并编辑布局文件如下。可以看到RecyclerView属于v7-支持库,如果你的androidsdk版本较旧的话,需要单独添加引用。

dependencies {
implementation ‘com.android.support:recyclerview-v7:27.1.1’
}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

2、RecyclerView的基本方法有两个。

   mRecyclerView.setLayoutManager(linearLayoutManager);
   mRecyclerView.setAdapter(mMyAdapter);

分别需要一个继承自RecyclerView.Adapter的mMyAdapter(需自己编写)和一个继承自RecyclerView.LayoutManager的布局管理器,系统已经给了3个常用的:LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager(瀑布布局)。
3、开始编写mMyAdapter的类RecycleAdapter

public class RecycleAdapter extends RecyclerView.Adapter

在继承RecyclerView.Adapter时,发现需要指定一个继承自RecyclerView.ViewHolder的类。这里解释一下ViewHolder,它封装了列表子项中用到的具体控件,对每个列表子项的实例进行缓存,负责显示子项。我们不能再像ListView那样直接操作View并且处理缓存,这里改为操作ViewHolder即可,而且ViewHolder已经帮我们实现了缓存。
4、实现ViewHolder类
从效果图上可以看出列表子项里包括一个ImageView、一个大TextView、一个小TextView。对应的实现代码如下:

 public class NormalHolder extends RecyclerView.ViewHolder {
        public ImageView icon;
        public TextView title;
        public TextView des;

        public NormalHolder(@NonNull View itemView) {
            super(itemView);
            icon = itemView.findViewById(R.id.imgIcon);
            title = itemView.findViewById(R.id.txtName);
            des = itemView.findViewById(R.id.txtDes);
        }
    }

列表子项的界面代码 custom_listcell.xml :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:orientation="horizontal">
    <ImageView
        android:id="@+id/imgIcon"
        android:layout_width="60dp"
        android:layout_height="60dp" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical">
        <TextView
            android:id="@+id/txtName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20dp" />
        <TextView
            android:id="@+id/txtDes"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="10dp" />
    </LinearLayout>
</LinearLayout>

列表子项的实体类代码 ListCellData.java:

public class ListCellData {
    private String controlName = "";
    private String controlDes = "";
    private int imgID;

    public ListCellData(String cn, String des, int imgid) {
        this.controlName = cn;
        this.controlDes = des;
        this.imgID = imgid;
    }

    public String getControlaName() { return controlName;}

    public String getControlDes() { return controlDes; }

    public void setControlDes(String controlDes) { this.controlDes = controlDes; }

    public int getImgID() { return imgID;}

    public void setImgID(int imgID) { this.imgID = imgID;}
}

5、具体实现RecycleAdapter (RecycleAdapter.java)

public class RecycleAdapter extends RecyclerView.Adapter<RecycleAdapter.NormalHolder> {

    private Context context;
    List<ListCellData> datasource;//用来接收列表数据源

    public RecycleAdapter(Context ct, List<ListCellData> ds) {
        context = ct;
        datasource = ds;
    }
    
    //创建ViewHolder,这里返回我们自己编写的NormalHolder
    @NonNull
    @Override
    public NormalHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new NormalHolder(LayoutInflater.from(context).inflate(R.layout.custom_listcell, null));
    }

    //填充视图,根据posotion取得具体数据项,并填充到界面上
    @Override
    public void onBindViewHolder(@NonNull final NormalHolder holder, int position)       {
        holder.title.setText(datasource.get(position).getControlaName());
        holder.des.setText(datasource.get(position).getControlDes());
        holder.icon.setImageResource(datasource.get(position).getImgID());
    }

    @Override
    public int getItemCount() {
        return datasource.size();
    } 
}

6、最后给出主Activity的代码(RecyclerActivity.java)。运行之后,就是本篇开始给出的效果了。

  private RecyclerView mRecyclerView;
  private RecycleAdapter mMyAdapter;
  private LinearLayoutManager linearLayoutManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler);
        initData();
        mRecyclerView = findViewById(R.id.recyclerView);
        mMyAdapter = new RecycleAdapter(this,datasource);
        linearLayoutManager = new LinearLayoutManager(this,OrientationHelper.VERTICAL,false);
       
        mRecyclerView.setLayoutManager(linearLayoutManager);
        mRecyclerView.setAdapter(mMyAdapter);
    }

分割线

添加分割线

mRecyclerView.addItemDecoration(new DividerItemDecoration(
                getActivity(), DividerItemDecoration.HORIZONTAL_LIST));

效果图:
AndroidStudio-3.2.1(十)RecyclerView_第2张图片
当然我们可以自定义分割线的样式,通过查看DividerItemDecoration的源码可知,它会读取系统主题中的@android:attr/listDivider作为 Item 的分割线(实质 Drawable ),同时还提供 setDrawable()方法,允许我们为分割线指定样式。感兴趣的可以自己写一个Drawable,设置代码如下:

//改成如下:
DividerItemDecoration decoration = new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);
decoration.setDrawable(getResources().getDrawable(R.drawable.divider,null));
mRecyclerView.addItemDecoration(decoration);

不同布局样式

切换不同的布局样式,只需设定不同的LayoutManager即可。
1、开篇给出了最常用的竖向LinearLayoutManager,下面演示横向的;

linearLayoutManager = new LinearLayoutManager(this,OrientationHelper.HORIZONTAL,false);

效果如图:
AndroidStudio-3.2.1(十)RecyclerView_第3张图片
2、GridLayoutManager.构造函数里需要指定Grid的列数。

 gridLayoutManager = new GridLayoutManager(this,3);
 mRecyclerView.setLayoutManager(gridLayoutManager );

效果图:
AndroidStudio-3.2.1(十)RecyclerView_第4张图片
3、最后是瀑布式布局,构造函数里需要指定列数和方向。

staggeredGridLayoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(staggeredGridLayoutManager);

为了展示出瀑布的效果,我们需要子项有不同的高度,在RecycleAdapter的RecycleAdapter方法里,我们加一个随机高度:

 ViewGroup.LayoutParams layoutParams = holder.title.getLayoutParams();
 layoutParams.height = new Random().nextInt(100) + 60;
 holder.title.setLayoutParams(layoutParams);

效果图:
AndroidStudio-3.2.1(十)RecyclerView_第5张图片

点击事件

RecyclerView 本身不提供点击事件,需要在onBindViewHolder事件里,自己配置控件的点击事件。虽然ListView 提供了点击事件,但是只能针对子项。而RecyclerView 可按需对任意子项 设置点击监听。
1、首先在RecycleAdapter中,添加点击监听事件:

 public interface IItemClickListener {
        void onItemClick(View view, int position);
        void onItemLongClick(View view, int posiition);
    }

    private IItemClickListener iItemClickListener;
    public void setOnItemClickListener(IItemClickListener listener) {
        iItemClickListener = listener;
    }

2、在onBindViewHolder中,将点击事件注册到控件上:

 if (iItemClickListener != null) {
            holder.title.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int pos = holder.getLayoutPosition();
                    iItemClickListener.onItemClick(holder.title, pos);
                }
            });
            holder.title.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    int pos = holder.getLayoutPosition();
                    iItemClickListener.onItemLongClick(holder.title, pos);
                    return  false;
                }
            });
        }

3、在RecyclerActivity中,设置点击事件的具体实现,并传入RecycleAdapter

mMyAdapter.setOnItemClickListener(new RecycleAdapter.IItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(RecyclerActivity.this, ((TextView)view).getText() + " click", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, int posiition) {
                Toast.makeText(RecyclerActivity.this, posiition + " Long click", Toast.LENGTH_SHORT).show();
                mMyAdapter.removeData(posiition);
            }
        });

我们对列表子项中的title(大TextView)控件设置了点击和长按事件,运行后即可看效果。

下拉刷新

下拉刷新主要是使用SwipeRefreshLayout控件,在原RecyclerView外包一层SwipeRefreshLayout,然后监听该控件的setOnRefreshListene事件即可。

  • 布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v4.widget.SwipeRefreshLayout
    android:id="@+id/refreshLayout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World!">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="#FFFF0000"
        android:dividerHeight="10dp"/>
    </android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
  • 监听事件:
 mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mMyAdapter.addList(InitData2());//每次刷新,往里插入5条记录
                        mRecyclerView.smoothScrollToPosition(0);
                        mSwipeRefreshLayout.setRefreshing(false);
                    }
                }, 500);
            }
        });
  • addList方法
    public void addList(List<ListCellData> ds){
        datasource.addAll(0,ds);
        notifyItemRangeInserted(0,ds.size());
    }
  • 其它参数
        //设置进度View样式的大小,只有两个值DEFAULT和LARGE
        mSwipeRefreshLayout.setSize(CircularProgressDrawable.LARGE );
        //设置进度View下拉的起始点和结束点,scale 是指设置是否需要放大或者缩小动画
        mSwipeRefreshLayout.setProgressViewOffset(true, -0, 100);
        //设置进度View下拉的结束点,scale 是指设置是否需要放大或者缩小动画
        mSwipeRefreshLayout.setProgressViewEndTarget(true, 180);
        //设置进度View的组合颜色,在手指上下滑时使用第一个颜色,在刷新中,会一个个颜色进行切换
        mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light,
                android.R.color.holo_red_light,
                android.R.color.holo_orange_light);
        //设置触发刷新的距离
        mSwipeRefreshLayout.setDistanceToTriggerSync(200);

你可能感兴趣的:(Android入门)