RecycleView的使用
1. 概述
RecyclerView架构,提供了一种插拔式的体验。只管回收与复用View,其他可自己设置,所以高度的解耦,并具有充分的定制自由。因此通过这个RecyclerView可轻松实现ListView、GirdView和瀑布流等效果。
- LayoutManager:布局管理器控制显示方式,如线性布局(ListView)、网格布局(GridView)和瀑布流布局。
- ItemDecoration:控制Item间的间隔样式
- ItemAnimator:控制Item增删的动画
- 点击和长按事件:需自定义
recyclerView = findView(R.id.test_recyclerview);
recyclerView .setLayoutManager(layout);//设置布局管理器
recyclerView .setAdapter(adapter)//设置adapter
recyclerView .setItemAnimator(new DefaultItemAnimator());//设置Item增删的动画
recyclerView .addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.HORIZONTAL));//添加分割线
2. 基本使用示例
2.1 实现线性布局ListView的效果
(1) RecycleviewTestActivity.java
package comi.example.liy.mytestdemo;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by liy on 2019-12-24 9:39
*/
public class RecycleviewTestActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<String> names;
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycleview);
initData();
recyclerView = findViewById(R.id.test_recycleview);
recyclerView.setLayoutManager(new LinearLayoutManager(this));//线性布局管理器,支持横向、纵向
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));//使用系统分割线
myAdapter = new MyAdapter();
recyclerView.setAdapter(myAdapter);
}
private void initData(){
names = new ArrayList<String>();
names.add("李小倾");
names.add("王小陌");
names.add("赵思齐");
names.add("钱卫聆");
names.add("孙云溪");
names.add("李龙飞");
names.add("李子恒");
names.add("颜绍");
names.add("刘明蕴");
names.add("郑星星");
for (int i = 0; i < 10; i++){
names.add("李" + (i+1));
}
}
class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(RecycleviewTestActivity.this).inflate(R.layout.item_recycleview, parent,false));
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position)
{
holder.tv.setText(names.get(position));
}
@Override
public int getItemCount()
{
return names.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.name);
}
}
}
}
(2) activity_recycleview.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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/test_recycleview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</android.support.constraint.ConstraintLayout>
(3) item_recycleview.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#06a7e2">
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="1"/>
</FrameLayout>
![](https://img.haomeiwen.com/i1892430/17033e472b90bbfe.png)
分割线
:在实际应用中我们也不需要去设计太过花哨的分割线,如果仅仅是希望item间有空隙,使用系统分割线或者设置item的margin即可实现。
- 使用系统默认分割线:本例通过调用
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL))
方法来实现系统提供的分割线效果,该分割线是系统默认的。 - 给Item的布局设置margin:达到和系统默认分割线一致的效果, item_recycleview.xml修改如下
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="1"
android:background="#06a7e2"
android:layout_marginTop="1dp"
android:layout_marginBottom="1dp"/>
</FrameLayout>
- 修改系统分割线的样式:可在style.xml中设置系统的listDivider、divider或dividerHeight属性来修改系统默认分割线的样式,如:
style.xml:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:listDivider">@drawable/divider_bg</item>
</style>
</resources>
divider_bg.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<gradient
android:startColor="#ff0000"
android:centerColor="#00ff00"
android:endColor="#0000ff"
android:type="linear" />
<size android:height="4dp"/>
</shape>
自定义分割线效果:
![](https://img.haomeiwen.com/i1892430/1205559ca42ccf6b.png)
2.2 实现网格布局GridView的效果
(1) RecycleviewTestActivity.java中修改布局管理器:recyclerView.setLayoutManager(new GridLayoutManager(this,3))
//recyclerView.setLayoutManager(new LinearLayoutManager(this));//线性布局管理器,支持横向、纵向
recyclerView.setLayoutManager(new GridLayoutManager(this,3));//网格布局管理器
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));//使用系统分割线
![](https://img.haomeiwen.com/i1892430/0e9fee937da79ed5.png)
修改布局管理器为GridLayoutManager以后,由上图的显示效果来看,明显此时系统默认的分割线效果不满足我们的需求,如果仅仅是希望item间有空隙,此时设置item的margin显然是最简单的方式(同时
注释掉
系统分割线的调用)。
(2) 修改item_recycleview.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="1"
android:background="#06a7e2"
android:layout_margin="1dp"/>
</FrameLayout>
(3) GridView效果展示
![](https://img.haomeiwen.com/i1892430/d3ecdd94753faf42.png)
2.3 实现瀑布流布局效果
瀑布流的实现和网格布局效果并无多大区别,只需在
网格布局效果
的基础上修改布局管理器为recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL))
,然后在适配器的onBindViewHolder方法中将item的固定高度设置为随机高度即可。
(1) 修改RecycleviewTestActivity.java
//recyclerView.setLayoutManager(new LinearLayoutManager(this));//线性布局管理器,支持横向、纵向
//recyclerView.setLayoutManager(new GridLayoutManager(this,3));//网格布局管理器
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));//瀑布布局管理器
//recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));//使用系统分割线(适用于线性布局)
@Override
public void onBindViewHolder(MyViewHolder holder, int position){
ViewGroup.LayoutParams lp = holder.tv.getLayoutParams();
lp.height = (int) (100 + Math.random() * 300);//随机高度
holder.tv.setLayoutParams(lp);
holder.tv.setText(names.get(position));
}
(2) item_recycleview.xml和网格布局的一致即可
(3) 瀑布流效果展示
![](https://img.haomeiwen.com/i1892430/d805e55a6f28308f.png)
3. 自定义点击或长按效果
系统没有提供ClickListener和LongClickListener,需要我们自己去实现。
实现的方式比较多,既可以通过recyclerView.addOnItemTouchListener去监听然后去判断手势,也可以通过在adapter中定义回调接口,这里以后者为例实现自定义点击或长按效果。
(1) RecycleviewTestActivity.java
package comi.example.liy.mytestdemo;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
/**
* Created by liy on 2019-12-24 9:39
*/
public class RecycleviewTestActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<String> names;
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycleview);
initData();
recyclerView = findViewById(R.id.test_recycleview);
//recyclerView.setLayoutManager(new LinearLayoutManager(this));//线性布局管理器,支持横向、纵向
//recyclerView.setLayoutManager(new GridLayoutManager(this,3));//网格布局管理器
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));//瀑布布局管理器
//recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));//使用系统分割线(适用于线性布局)
//recyclerView.addItemDecoration(new MyDividerItemDecoration(this,MyDividerItemDecoration.VERTICAL));//自定义分割线(适用于线性布局)
//recyclerView.addItemDecoration(new MyDividerGridItemDecoration(this));//自定义分割线(适用于网格布局)
recyclerView.setItemAnimator(new DefaultItemAnimator());//设置item增删的动画(默认效果,可省略)
myAdapter = new MyAdapter(this,names);
recyclerView.setAdapter(myAdapter);
initListener();//Activity中设置监听
}
private void initData(){
names = new ArrayList<String>();
names.add("李小倾");
names.add("王小陌");
names.add("赵思齐");
names.add("钱卫聆");
names.add("孙云溪");
names.add("李龙飞");
names.add("李子恒");
names.add("颜绍");
names.add("刘明蕴");
names.add("郑星星");
for (int i = 0; i < 10; i++){
names.add("李" + (i+1));
}
}
private void initListener(){
myAdapter.setOnItemClickLitener(new MyAdapter.OnItemClickLitener()
{
@Override
public void onItemClick(View view, int position) {
Toast.makeText(RecycleviewTestActivity.this, position + " click",Toast.LENGTH_SHORT).show();
addData(position);
}
@Override
public void onItemLongClick(View view, int position) {
Toast.makeText(RecycleviewTestActivity.this, position + " long click",Toast.LENGTH_SHORT).show();
removeData(position);
}
});
}
public void addData(int position){
names.add(position,"newName");//在当前位置添加
//names.add("newName");//在末尾添加
myAdapter.notifyItemInserted(position);//更新数据集刷新界面
}
public void removeData(int position){
names.remove(position);
myAdapter.notifyItemRemoved(position);//更新数据集刷新界面
}
static class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{
private Context context;
private List<String> names;
public MyAdapter(Context context, List<String> names) {![waterfall.gif](https://img.haomeiwen.com/i1892430/e50ef69c88426aba.gif?imageMogr2/auto-orient/strip)
this.context = context;
this.names = names;
}
//定义一个回调接口
public interface OnItemClickLitener{
void onItemClick(View view, int position);
void onItemLongClick(View view , int position);
}
private OnItemClickLitener mOnItemClickLitener;
public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener) {
this.mOnItemClickLitener = mOnItemClickLitener;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_recycleview, parent,false));
return holder;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, int position)
{
ViewGroup.LayoutParams lp = holder.tv.getLayoutParams();
lp.height = (int) (100 + Math.random() * 300);//随机高度
holder.tv.setLayoutParams(lp);
holder.tv.setText(names.get(position));
// 如果设置了回调,则设置点击事件
if (mOnItemClickLitener != null) {
holder.tv.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemClick(holder.itemView, pos);//回调我们设置的监听
}
});
holder.tv.setOnLongClickListener(new View.OnLongClickListener()
{
@Override
public boolean onLongClick(View v)
{
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
return true;//返回true自己消费掉,事件不会再向下传递触发点击事件
}
});
}
}
@Override
public int getItemCount()
{
return names.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.name);
}
}
}
}
(2) 自定义点击或长按效果
![](https://img.haomeiwen.com/i1892430/1fbb8f607358d7c0.gif)