RecyclerView使用总结-------上

前言

学习使用RecyclerView也有一段时间,一直都没有时间做个总结,就抽空想把RecyclerView的一些使用方法总结出来,方便大家也方便自己查阅。

简介

RecyclerView是support.v7包中的控件,可以说是ListView和GridView的增强升级版。既然官方已经提供了ListView和GridView,为什么还要提供RecyclerView呢?相对于来说RecyclerView肯定是比他们具有一些没有的优势。总的来说就是:低耦合高内聚,RecyclerView已经标准化ViewHolder,我们自定义的ViewHoler需要继承 RecyclerView.ViewHolder,然后在构造方法中初始化控件。通过设置不同的LayoutManager,可以实现Item不同的布局方式。插拔式的使用体验,结合ItemDecoration , ItemAnimator,ItemTouchHelper,则可以实现Item之间的分割线、动画,滑动拖拽等炫酷效果,这是ListView、GridView等控件难以企及的。


RecyclerView的简单使用

首先添加依赖库:

implementation 'com.android.support:recyclerview-v7:27.1.1'

activity的布局:



Item的布局:



    
        
    

在Activity中获取RecyclerView,并设置LayoutManager以及Adapter:

//初始化数据
List datas = new ArrayList<>();
for(int i=0;i<10;i++){
     datas.add("item "+i);
}

recyclerView = findViewById(R.id.recycler_view);
//设置LayoutManager为LinearLayoutManager
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//设置Adapter
recyclerView.setAdapter(new GeneralAdapter(this,datas));

这里的LayoutManager就是RecyclerView的布局管理器,用以实现Item不同布局排列方式,RecyclerView必须调用setLayoutManager设置布局管理器。RecyclerView中默认带有三个布局管理器:LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager,这三种布局管理器都支持横向和纵向排列以及反向滑动,这个在后面会讲解到。

Adapter的代码:

public class GeneralAdapter extends RecyclerView.Adapter {
    //当前上下文对象
    Context context;
    //RecyclerView填充Item数据的List对象
    List datas;

    public GeneralAdapter(Context context,List datas){
        this.context = context;
        this.datas = datas;
    }

    //创建ViewHolder
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //实例化得到Item布局文件的View对象
        View v = View.inflate(context, R.layout.item_recycler,null);
        //返回MyViewHolder的对象
        return new MyViewHolder(v);
    }

    //绑定数据
    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.textView.setText(datas.get(position));
    }

    //返回Item的数量
    @Override
    public int getItemCount() {
        return datas.size();
    }

    //继承RecyclerView.ViewHolder抽象类的自定义ViewHolder
    class MyViewHolder extends RecyclerView.ViewHolder{
        TextView textView;

        public MyViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.text);
        }
    }
}

这里的Adapter与ListView的Adapter相差不大,只不过这里是继承自RecyclerView.Adapter这个抽象类。后面是一个必须继承自RecyclerView.ViewHolder抽象类的ViewHolder的泛型约束,也就是GeneralAdapter.MyViewHolder这个内部类,这个在前言中讲到过。RecyclerView.Adapter抽象类有三个必须实现的抽象方法:

public abstract VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType);

public abstract void onBindViewHolder(@NonNull VH holder, int position);

public abstract int getItemCount();

具体的用途上方Adapter的代码中都有注释。

以上就是RecyclerView的简单使用了,献上效果图:


RecyclerView使用总结-------上_第1张图片
Screenshot_2018-05-14-16-12-23.png

item的点击事件

在RecyclerView当中,并没有如同ListView那样并直接提供类似setOnItemClickListener( )和setOnItemLongClickListener ( )的方法。如果要实现Item的点击事件,我们可以自己去实现。

这里给出两种方法:

① 在Adapter里面直接对控件做点击事件
② 写接口,在Activity或Fragment上实现接口中定义的方法

方法一:

@Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
        holder.textView.setText(datas.get(position));
        //直接对控件做点击事件
        holder.textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context,holder.textView.getText()+"被点击了",
                        Toast.LENGTH_SHORT).show();
            }
        });
    }

方法二:

定义回调接口:

/**
 * 设置回调接口
 */
public interface OnItemClickListener {
    void onItemClick(View view, int position);
}
/**
 * 设置长按回调接口
 */
public interface OnItemLongClickListener {
    boolean onItemLongClick(View view, int position);
}

Adapter中的部分代码:

public class GeneralAdapter extends RecyclerView.Adapter {
    //当前上下文对象
    Context context;
    //RecyclerView填充Item数据的List对象
    List datas;

    public GeneralAdapter(Context context,List datas){
        this.context = context;
        this.datas = datas;
    }


    /**
     * 事件回调监听
     */
    private OnItemClickListener onItemClickListener;
    private OnItemLongClickListener onItemLongClickListener;
    /**
     * 设置回调监听
     *
     * @param listener
     */
    public void setOnItemClickListener(OnItemClickListener listener) {
        this.onItemClickListener = listener;
    }

    public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
        this.onItemLongClickListener = onItemLongClickListener;
    }
   
    。。。。。。。。。

    //绑定数据
    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
        holder.textView.setText(datas.get(position));
        //通过接口回调响应点击事件
        holder.textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(onItemClickListener != null){
                    onItemClickListener.onItemClick(view,position);
                }

            }
        });
        //通过接口回调响应长按事件
        holder.textView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                if(onItemLongClickListener != null){
                    return onItemLongClickListener.onItemLongClick(view,position);
                }
                return false;
            }
        });
    }

    。。。。。。。

}

Activity中使用:

        //点击事件
        adapter.setOnItemClickListener(new GeneralAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(GeneralActivity.this,datas.get(position)+"被点击了",
                        Toast.LENGTH_SHORT).show();
            }
        });
        //长按事件
        adapter.setOnItemLongClickListener(new GeneralAdapter.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(View view, int position) {
                Toast.makeText(GeneralActivity.this,datas.get(position)+"被长按了",
                        Toast.LENGTH_SHORT).show();
                return true;
            }
        });

效果图:


RecyclerView使用总结-------上_第2张图片
Screenshot_2018-05-15-14-55-15.png
RecyclerView使用总结-------上_第3张图片
Screenshot_2018-05-15-15-15-16.png

布局管理器

前文说到RecyclerView的使用必须调用setLayoutManager来设置布局管理器,是为什么呢?因为RecyclerView不像ListView Item只有垂直排列一种排列方式,而RecyclerView通过setLayoutManager设置不同的布局管理器,Item就会按照设置的布局管理器的排列方式来排列。如果不调用setLayoutManager来设置布局管理器就会导致RecyclerView不知道它的Item如何布局,界面上就会一片空白。RecyclerView自身带有三种默认的布局管理器:LinearLayoutManagerGridLayoutManagerStaggeredGridLayoutManager

LinearLayoutManager线性布局管理器

LinearLayoutManager就如同它的翻译一样,线性布局管理器。设置这个布局管理器的话,可以设置它的排列方向,通过setOrientation()函数设置,参数可以是水平或者垂直。如果是垂直的话,那就跟ListView一模一样了。也就是前面简单使用中的例子。

LinearLayoutManager布局管理器默认使用垂直排列布局,而需要水平排列布局的话则可以通过LinearLayoutManager对象的setOrientation方法设置,此方法接收int类型的值,分别为RecyclerView中的两个Int常量:

public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
public static final int VERTICAL = LinearLayout.VERTICAL;

HORIZONTAL :代表水平排列
VERTICAL :代表垂直排列

也可以在new出LinearLayoutManager对象的时候调用它的三个参数的构造方法设置它的布局排列方向。

public LinearLayoutManager(Context context, @RecyclerView.Orientation int orientation,
boolean reverseLayout)
第二个参数就是这个布局管理器的排列方式,依旧是传入上方两个常量值中的其中一个。第三个参数一般传false,它的用途是当为true时数据和滑动都是反向的。具体意思可以自行实验。

在前面的代码基础上,放上水平排列的代码

Item布局:



    
        
    

Activity中的代码:

public class GeneralActivity extends AppCompatActivity {
    
    RecyclerView recyclerView;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_general);

        //初始化数据
        List datas = new ArrayList<>();
        for(int i=0;i<10;i++){
            datas.add("item "+i);
        }

        recyclerView = findViewById(R.id.recycler_view);
        //通过setOrientation设置或者直接在构造方法中设置
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(RecyclerView.HORIZONTAL);

        //设置LayoutManager为LinearLayoutManager
        recyclerView.setLayoutManager(new LinearLayoutManager(this,RecyclerView.HORIZONTAL,false));
        //recyclerView.setLayoutManager(linearLayoutManager);
        //设置Adapter
        recyclerView.setAdapter(new GeneralAdapter(this,datas));
    }
}

Adapter中无变化,就不放上来筹字数了。

呈上效果图:

RecyclerView使用总结-------上_第4张图片
Screenshot_2018-05-14-17-08-20.png
GridLayoutManager网格布局管理器

网格布局管理器,顾名思义Item已网格方式排列。跟线性布局管理器一样,也支持通过setOrientation()或者构造方法来设置Item的排列方向。

垂直排列:

//设置LayoutManager为GridLayoutManager
recyclerView.setLayoutManager(new GridLayoutManager(this,3));

这里使用了GridLayoutManager两个参数的构造方法,第二个参数Item有几行或者几列。之所以这么说,是因为当水平排列时,就是有几行。垂直排列时就是有几列。当不设置排列方式时,默认使用垂直排列。

垂直排列效果图:

RecyclerView使用总结-------上_第5张图片
Screenshot_2018-05-15-13-54-29.png

水平排列:

GridLayoutManager gridLayoutManager = new GridLayoutManager(this,3);
gridLayoutManager.setOrientation(RecyclerView.HORIZONTAL);
//设置LayoutManager为GridLayoutManager
recyclerView.setLayoutManager(gridLayoutManager);

效果图:

RecyclerView使用总结-------上_第6张图片
Screenshot_2018-05-15-13-55-42.png
StaggeredGridLayoutManager 瀑布流布局管理器

通过设置StaggeredGridLayoutManager则可以实现炫酷的瀑布流效果。它最常用的构造函数就一个,StaggeredGridLayoutManager(int spanCount, int orientation),spanCount代表每行或每列的Item个数,orientation代表列表的方向,竖直或者水平。
要实现瀑布流效果(仅讨论竖直方向的瀑布流样式),每一个Item的高度要有所差别,如果所有的item的高度相同,就和网格样式是一样的展示效果。示例中就实现两中不同高度的Item,一个高度为100dp,一个高度为200dp。

item1布局:



    
        
    

Item2布局:



    
        
    

Adapter的代码:

public class StaggeredApapter extends RecyclerView.Adapter {

    //当前上下文对象
    Context context;
    //RecyclerView填充Item数据的List对象
    List datas;

    public StaggeredApapter(Context context,List datas){
        this.context = context;
        this.datas = datas;
    }

    @Override
    public int getItemViewType(int position) {
        if(position %2 == 0){
            return 0;
        }else{
            return 2;
        }
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View v;
        if(viewType == 0){
            v = View.inflate(context,R.layout.item_recycler,null);
        }else{
            v = View.inflate(context,R.layout.item2_recycler,null);
        }

        return new MyViewHolder(v);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.textView.setText(datas.get(position));
    }

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

    class MyViewHolder extends RecyclerView.ViewHolder{

        TextView textView;

        public MyViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.text);
        }
    }
}

这里Adapter的代码相对于之前,多重写了一个public int getItemViewType(int position)一个方法,这个方法是根据当前Item的position返回当前Item的类型。这里就是实现瀑布流的关键。可以看到在onCreateViewHolder方法中,我们根据不同的ViewType,初始化了不同 Item布局。这样Item的位置不一样, 那么它的高度就可能不一样。

Activity中的代码:

public class StaggeredLayoutActivity extends AppCompatActivity {
    RecyclerView recyclerView;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_general);

        //初始化数据
        List datas = new ArrayList<>();
        for(int i=0;i<20;i++){
            datas.add("item "+i);
        }
        recyclerView = findViewById(R.id.recycler_view);
        //设置LayoutManager为StaggeredGridLayoutManager
        recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2,RecyclerView.VERTICAL));
        //设置Adapter
        recyclerView.setAdapter(new StaggeredApapter(this,datas));

    }
}

效果图:

RecyclerView使用总结-------上_第7张图片
Screenshot_2018-05-15-14-42-34.png

未完待续。。。。。。

敬请期待下篇的高级操作,Item间隔线、Item滑动删除、Item拖拽、Item添加移除动画、滑动动画、添加Footer,Header、分组、上拉加载、下拉刷新等

你可能感兴趣的:(RecyclerView使用总结-------上)