(转)RecyclerView常用功能

RecyclerView是support:recyclerview-v7中提供的控件,最低兼容到android 3.0版本。

官方介绍RecyclerView为在有限的窗口展现大量数据的控件。拥有类似功能的控件有ListView、GridView以及被Google遗弃的Gallery等,为毛已经有了它们,Google还推出RecyclerView呢,那就要说说RecyclerView所具有的一些优势了。

那RecyclerView到底有啥优势呢?总结起来六颗字:低耦合高类聚。RecyclerView已经标准化ViewHolder,我们自定义的ViewHoler需要继承 RecyclerView.ViewHolder,然后在构造方法中初始化控件,后面会有具体介绍。通过设置不同的LayoutManager,以及结合ItemDecoration , ItemAnimator,ItemTouchHelper,可以实现非常炫酷的效果,这些是ListView等控件难以企及的。

基本使用:

1.使用前需要在在gradle中添加依赖

`implementation 'com.android.support:recyclerview-v7:27.0.2'  `

2.编写代码,首先我们需要在Xml中写RecyclerView的布局,

```

android:id="@+id/recyclerView"  

android:layout_width="match_parent"  

android:layout_height="match_parent"/>    

```

然后在activity中获取RecyclerView,并设置LayoutManager以及adapter

//通过findViewById拿到RecyclerView实例  

`mRecyclerView =   findViewById(R.id.recyclerView);  `

//设置RecyclerView管理器  

mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));  

//初始化适配器  

mAdapter =new MyRecyclerViewAdapter(list);   

//设置添加或删除item时的动画,这里使用默认动画  

mRecyclerView.setItemAnimator(new DefaultItemAnimator());  

//设置适配器  

mRecyclerView.setAdapter(mAdapter);  

下面是MyRecyclerViewAdapter的代码:

[java] view plain copy

package com.sharejoys.recyclerviewdemo.actvity;  


import android.support.v7.widget.RecyclerView;  

import android.view.LayoutInflater;  

import android.view.View;  

import android.view.ViewGroup;  

import android.widget.TextView;  


import com.sharejoys.recyclerviewdemo.R;  


import java.util.List;  


/**

 * Created by 青青-子衿 on 2018/1/15.

 */  



public class MyRecyclerViewAdapterextends RecyclerView.Adapter {  

private List list;  


public MyAdapter(List list) {  

this.list = list;  

    }  


@Override  

public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  

View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_base_use, parent,false);  

MyAdapter.ViewHolder viewHolder =new MyAdapter.ViewHolder(view);  

return viewHolder;  

    }  


@Override  

public void onBindViewHolder(MyAdapter.ViewHolder holder, int position) {  

        holder.mText.setText(list.get(position));  

    }  


@Override  

public int getItemCount() {  

return list.size();  

    }  


class ViewHolder extends RecyclerView.ViewHolder {  

        TextView mText;  

        ViewHolder(View itemView) {  

super(itemView);  

            mText = itemView.findViewById(R.id.item_tx);  

        }  

    }  

}  

这里item_normal的布局也非常简单

[html] view plain copy


xmlns:android="http://schemas.android.com/apk/res/android"  

android:layout_width="match_content"  

android:layout_height="wrap_content"  

android:orientation="vertical">  


android:id="@+id/item_tx"  

android:layout_width="match_content"  

android:layout_height="wrap_content"  

android:gravity="center"  

android:padding="10dp"  

android:layout_gravity="center_horizontal"  

android:text="Item"/>  



然后我们运行效果如下

(转)RecyclerView常用功能_第1张图片

从例子也可以看出来,RecyclerView的用法并不比ListView复杂,反而更灵活好用,它将数据、排列方式、数据的展示方式都分割开来,因此可定制型,自定义的形式也非常多,非常灵活。

设置横向布局:

[java] view plain copy

mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));  

(转)RecyclerView常用功能_第2张图片

设置网格布局:

[java] view plain copy

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

(转)RecyclerView常用功能_第3张图片

设置瀑布流:

[java] view plain copy

mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));  

(转)RecyclerView常用功能_第4张图片

如果第二个参数可以设置为横向的,则效果如下:

(转)RecyclerView常用功能_第5张图片

从以上可知,我们可以通过设置不同的管理器,实现不同的效果

LinearLayoutManager:以线性布局展示,可以设置横向和纵向

GridLayoutManager:以网格形式展示,类似GridView效果

StaggeredGridLayoutManager:以瀑布流形式的效果

RecyclerView条目之间默认没有分割线,那是否可以像ListView一样设置divider以及dividerHight搞一条分割线出来呢,答案是不可以的,google并没有提供这样的属性。但是谷歌为我们提供了可以定制的解决办法,那就是以下要说ItemDecoration

利用ItemDecoration实现条目分割线

ItemDecoration是谷歌定义的可用于画分割线的类, 是抽象的,需要我们自己去实现

[java] view plain copy

/**

   * An ItemDecoration allows the application to add a special drawing and layout offset

   * to specific item views from the adapter's data set. This can be useful for drawing dividers

   * between items, highlights, visual grouping boundaries and more.

   *

   * 

All ItemDecorations are drawn in the order they were added, before the item

   * views (in {@link ItemDecoration#onDraw(Canvas, RecyclerView, RecyclerView.State) onDraw()}

   * and after the items (in {@link ItemDecoration#onDrawOver(Canvas, RecyclerView,

   * RecyclerView.State)}.

   */  

public abstract static class ItemDecoration {  

public void onDraw(Canvas c, RecyclerView parent, State state) {  

          onDraw(c, parent);  

      }  

@Deprecated  

public void onDraw(Canvas c, RecyclerView parent) {  

      }  


public void onDrawOver(Canvas c, RecyclerView parent, State state) {  

          onDrawOver(c, parent);  

      }  


@Deprecated  

public void onDrawOver(Canvas c, RecyclerView parent) {  

      }  



@Deprecated  

public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {  

outRect.set(0, 0, 0, 0);  

      }  


public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {  

          getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),  

                  parent);  

      }  

  }  

当我们通过

[java] view plain copy

mRecyclerView.addItemDecoration();  

    onDraw: 该方法可以在RecyclerView的画布上画任何装饰,且是在 the item views 被绘制之前回调

    onDrawOver:该方法可以在RecyclerView的画布上画任何装饰,且是在 the item views 被绘制之后回调

    getItemOffsets :可以在该方法中为the item views添加偏移量

下面我们可以就通过继承ItemDecoration为RecyclerView添加分割线。

DividerItemDecoration的代码如下: 

[java] view plain copy

package com.sharejoys.mvpdemo.ui.customview;  


import android.content.Context;  

import android.content.res.TypedArray;  

import android.graphics.Canvas;  

import android.graphics.Rect;  

import android.graphics.drawable.Drawable;  

import android.support.annotation.IntDef;  

import android.support.v4.view.ViewCompat;  

import android.support.v7.widget.LinearLayoutManager;  

import android.support.v7.widget.RecyclerView;  

import android.view.View;  


/**

 * Date: 2018/1/14

 *

 * @author 青青-子衿

 * @since 1.0

 */  


public class DividerItemDecoration extends RecyclerView.ItemDecoration {  

@OrientationType  

private int mOrientation = LinearLayoutManager.VERTICAL;  

private Drawable mDivider;  


private int[] attrs = new int[]{  

            android.R.attr.listDivider  

    };  


public DividerItemDecoration(Context context, @OrientationType int orientation) {  

        TypedArray typedArray = context.obtainStyledAttributes(attrs);  

mDivider = typedArray.getDrawable(0);  

        typedArray.recycle();  

        setOrientation(orientation);  

    }  


private void setOrientation(@OrientationType int orientation) {  

if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {  

throw new IllegalArgumentException("传入的布局类型不合法");  

        }  

this.mOrientation = orientation;  

    }  


@Override  

public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {  

//调用这个绘制方法,RecyclerView会回调该绘制方法,需要我们自己去绘制条目的间隔线  

if (mOrientation == LinearLayoutManager.VERTICAL) {  

//垂直  

            drawVertical(c, parent);  

}else {  

//水平  

            drawHorizontal(c, parent);  

        }  

    }  


private void drawVertical(Canvas c, RecyclerView parent) {  

// 画水平线  

int left = parent.getPaddingLeft();  

int right = parent.getWidth() - parent.getPaddingRight();  

int childCount = parent.getChildCount();  

for (int i = 0; i < childCount; i++) {  

            View child = parent.getChildAt(i);  


            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();  

int top = child.getBottom() + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child));  

int bottom = top + mDivider.getIntrinsicHeight();  

            mDivider.setBounds(left, top, right, bottom);  

            mDivider.draw(c);  

        }  

    }  


private void drawHorizontal(Canvas c, RecyclerView parent) {  

int top = parent.getPaddingTop();  

int bottom = parent.getHeight() - parent.getPaddingBottom();  

int childCount = parent.getChildCount();  

for (int i = 0; i < childCount; i++) {  

            View child = parent.getChildAt(i);  


            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();  

int left = child.getRight() + params.rightMargin + Math.round(ViewCompat.getTranslationX(child));  

int right = left + mDivider.getIntrinsicHeight();  

            mDivider.setBounds(left, top, right, bottom);  

            mDivider.draw(c);  

        }  

    }  


@Override  

public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {  

//获得条目的偏移量(所有的条目都会回调一次该方法)  

if (mOrientation == LinearLayoutManager.VERTICAL) {  

//垂直  

outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());  

}else {  

//水平  

outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);  

        }  

    }  


@IntDef({LinearLayoutManager.VERTICAL, LinearLayoutManager.HORIZONTAL})  

public @interface OrientationType {  

    }  

}  

然后在activity设置水平方向

[java] view plain copy

mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);   

mRecyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));  

(转)RecyclerView常用功能_第6张图片

竖直方向:

[java] view plain copy

mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONAL, false);   

mRecyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.HORIZONAL))  

(转)RecyclerView常用功能_第7张图片

这里的分割线是默认的,我们可以在主题中去设置分割线的颜色

[html] view plain copy




@color/colorPrimary  

@color/colorPrimaryDark  

@color/colorAccent  

@drawable/bg_recyclerview_divider  


bg_recyclerview_divider.xml

[html] view plain copy


android:shape="rectangle">  


android:centerColor="#ff00ff00"  

android:endColor="#ff0000ff"  

android:startColor="#ffff0000"  

android:type="linear"/>  


android:width="10dp"  

android:height="10dp"/>  



运行后效果如下

(转)RecyclerView常用功能_第8张图片

以上的分割线只适用在LinearLayoutManager的相关布局中。

对于GridLayoutManager布局是不适用的。需要我们单独写一个。

以下是对于GridLayoutManager布局的分割线代码

[java] view plain copy

package com.sharejoys.recyclerviewdemo.view;  


import android.content.Context;  

import android.content.res.TypedArray;  

import android.graphics.Canvas;  

import android.graphics.Rect;  

import android.graphics.drawable.Drawable;  

import android.support.v7.widget.GridLayoutManager;  

import android.support.v7.widget.RecyclerView;  

import android.view.View;  


/**

 * Date: 2018/1/14 

 *

 * @author 青青-子衿

 * @since 1.0

 */  


public class DividerGridViewItemDecoration extends RecyclerView.ItemDecoration {  

private Drawable mDivider;  

private int[] attrs = new int[]{  

            android.R.attr.listDivider};  


public DividerGridViewItemDecoration(Context context) {  

        TypedArray typedArray = context.obtainStyledAttributes(attrs);  

mDivider = typedArray.getDrawable(0);  

        typedArray.recycle();  

    }  


@Override  

public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {  

        drawVertical(c, parent);  

        drawHorizontal(c, parent);  

    }  


private void drawVertical(Canvas c, RecyclerView parent) {  

//绘制垂直间隔线(垂直的矩形)  

int childCount = parent.getChildCount();  

for (int i = 0; i < childCount; i++) {  

            View child = parent.getChildAt(i);  

            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();  

int left = child.getRight() + params.rightMargin;  

int right = left + mDivider.getIntrinsicWidth();  

int top = child.getTop() - params.topMargin;  

int bottom = child.getBottom() + params.bottomMargin;  


            mDivider.setBounds(left, top, right, bottom);  

            mDivider.draw(c);  

        }  

    }  


private void drawHorizontal(Canvas c, RecyclerView parent) {  

//绘制水平分割线  

int childCount = parent.getChildCount();  

for (int i = 0; i < childCount; i++) {  

            View child = parent.getChildAt(i);  

            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();  

int left = child.getLeft() - params.leftMargin;  

int right = child.getRight() + params.rightMargin + mDivider.getIntrinsicWidth();  

int top = child.getBottom() + params.bottomMargin;  

int bottom = top + mDivider.getIntrinsicHeight();  


            mDivider.setBounds(left, top, right, bottom);  

            mDivider.draw(c);  

        }  

    }  


@Override  

public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {  

// 四个方向的偏移值  

int right = mDivider.getIntrinsicWidth();  

int bottom = mDivider.getIntrinsicHeight();  


        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();  

int itemPosition = params.getViewAdapterPosition();  

if (isLastColum(itemPosition, parent)) {  

right =0;  

        }  


if (isLastRow(itemPosition, parent)) {  

bottom =0;  

        }  

outRect.set(0, 0, right, bottom);  

    }  


/**

     * 是否最后一行

     */  

private boolean isLastRow(int itemPosition, RecyclerView parent) {  

int spanCount = getSpanCount(parent);  

if (spanCount != -1) {  

int childCount = parent.getAdapter().getItemCount();  

int lastRowCount = childCount % spanCount;  

//最后一行的数量小于spanCount  

if (lastRowCount == 0 || lastRowCount < spanCount) {  

return true;  

            }  

        }  


return false;  

    }  



/**

     * 根据parent获取到列数

     */  

private int getSpanCount(RecyclerView parent) {  

        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();  

if (layoutManager instanceof GridLayoutManager) {  

            GridLayoutManager lm = (GridLayoutManager) layoutManager;  

int spanCount = lm.getSpanCount();  

return spanCount;  

        }  

return -1;  

    }  


/**

     * 判断是否是最后一列

     */  

private boolean isLastColum(int itemPosition, RecyclerView parent) {  

int spanCount = getSpanCount(parent);  

if (spanCount != -1) {  

if ((itemPosition + 1) % spanCount == 0) {  

return true;  

            }  

        }  

return false;  

    }  

}  

我们在activity中使用该分割线

[java] view plain copy

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

mRecyclerView.addItemDecoration(new DividerGridViewItemDecoration(this));  

(转)RecyclerView常用功能_第9张图片

点击事件

RecyclerView并没有像ListView的那样可以设置点击事件以及长按点击事件,这个需要我们可以在adapter中去设置回调的方式实现,具体代码如下:

MyRecyclerViewAdapter的代码如下:

[java] view plain copy

package com.sharejoys.recyclerviewdemo.actvity;  


import android.support.v7.widget.RecyclerView;  

import android.view.LayoutInflater;  

import android.view.View;  

import android.view.ViewGroup;  

import android.widget.TextView;  


import com.sharejoys.recyclerviewdemo.R;  


import java.util.List;  


/**

 * Created by 青青-子衿 on 2018/1/15.

 */  



public class MyRecyclerViewAdapter extends RecyclerView.Adapter {  

private List list;  

private OnItemClickListener onItemClickListener;  

private OnItemLongClickListener onItemLongClickListener;  


/**

     * 设置点击事件

     */  

public void setOnItemClickListener(OnItemClickListener onItemClickListener) {  

this.onItemClickListener = onItemClickListener;  

    }  


/**

     * 设置长按点击事件

     */  

public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {  

this.onItemLongClickListener = onItemLongClickListener;  

    }  


public MyRecyclerViewAdapter(List list) {  

this.list = list;  

    }  


@Override  

public MyRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  

View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_base_use, parent,false);  

MyRecyclerViewAdapter.ViewHolder viewHolder =new MyRecyclerViewAdapter.ViewHolder(view);  

return viewHolder;  

    }  


@Override  

public void onBindViewHolder(MyRecyclerViewAdapter.ViewHolder holder, int position) {  

        holder.mText.setText(list.get(position));  

int adapterPosition = holder.getAdapterPosition();  

if (onItemClickListener != null) {  

holder.itemView.setOnClickListener(new MyOnClickListener(position, list.get(adapterPosition)));  

        }  

if (onItemLongClickListener != null) {  

holder.itemView.setOnLongClickListener(new MyOnLongClickListener(position, list.get(adapterPosition)));  

        }  

    }  


@Override  

public int getItemCount() {  

return list.size();  

    }  


class ViewHolder extends RecyclerView.ViewHolder {  

        TextView mText;  


        ViewHolder(View itemView) {  

super(itemView);  

            mText = itemView.findViewById(R.id.item_tx);  

        }  

    }  


private class MyOnLongClickListener implements View.OnLongClickListener {  

private int position;  

private String data;  


public MyOnLongClickListener(int position, String data) {  

this.position = position;  

this.data = data;  

        }  


@Override  

public boolean onLongClick(View v) {  

            onItemLongClickListener.onItemLongClick(v, position, data);  

return true;  

        }  

    }  


private class MyOnClickListener implements View.OnClickListener {  

private int position;  

private String data;  


public MyOnClickListener(int position, String data) {  

this.position = position;  

this.data = data;  

        }  


@Override  

public void onClick(View v) {  

            onItemClickListener.onItemClick(v, position, data);  

        }  

    }  



public interface OnItemClickListener {  

void onItemClick(View view, int position, String data);  

    }  


public interface OnItemLongClickListener {  

void onItemLongClick(View view, int position, String data);  

    }  


}  

activity中设置监听:

[java] view plain copy

mAdapter.setOnItemClickListener(new MyRecyclerViewAdapter.OnItemClickListener() {  

@Override  

public void onItemClick(View view, int position, String data) {  

Toast.makeText(MainActivity.this, "您点击了:  " + data, Toast.LENGTH_SHORT).show();  

        }  

    });  

mAdapter.setOnItemLongClickListener(new MyRecyclerViewAdapter.OnItemLongClickListener() {  

@Override  

public void onItemLongClick(View view, int position, String data) {  

Toast.makeText(MainActivity.this, "您长按点击了:  " + data, Toast.LENGTH_SHORT).show();  

        }  

    });  

运行后效果如下:

(转)RecyclerView常用功能_第10张图片
(转)RecyclerView常用功能_第11张图片

ItemAnimator

我们可以为RecyclerView设置增加和删除动画,这里我们可以使用默认动画

[java] view plain copy

//设置添加或删除item时的动画,这里使用默认动画  

mRecyclerView.setItemAnimator(new DefaultItemAnimator());  

然后在Adapter中增加删除和添加数据的方法

[java] view plain copy

/**

  * 插入一条数据

  *

  * @param index 下标

  * @param s     数据

  */  

public void addItem(int index, String s) {  

     list.add(index, s);  

     notifyItemInserted(index);  

 }  


/**

  * 删除一条数据

  *

  * @param index 下标

  */  

public void deleteItem(int index) {  

     list.remove(index);  

     notifyItemRemoved(index);  

 }  

activty调用删除和添加方法后效果如下

RecycleView还有一些其他用法,比如结合ItemTouchHelper实现item的拖拽效果,可以自定义增加header和footer(类似Listview)

最后附上demo地址

本文来自:https://blog.csdn.net/tuike/article/details/79064750

你可能感兴趣的:((转)RecyclerView常用功能)