Android 新控件 RecycleView 源码分析一

本贴最后更新于 2816 天前,其中的信息可能已经事过景迁

RecyclerView 源码分析一

原文

1.简介

RecyclerView 已经出来很久了,是 support-v7 下面的新控件,现在已经完全取代了 ListView 和 GridView,在项目中如果要使用的话要引入 support-v7 这个包,如果是 AS 下 编程的话直接引用就行。在 bulid 下面添加这行代码

compile 'com.android.support:recyclerview-v7:23.3.0'

就可以了。

官网地址:[RecyclerView API](https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html)

官网上面的解释是:A flexible view for providing a limited window into a large data set. ,意思是 在有限的窗口内设置一个可变的的大量数据视图。

public class RecyclerView
extends [ViewGroup](https://developer.android.com/reference/android/view/ViewGroup.html) ``implements [ScrollingView](https://developer.android.com/reference/android/support/v4/view/ScrollingView.html), [NestedScrollingChild](https://developer.android.com/reference/android/support/v4/view/NestedScrollingChild.html)

| java.lang.Object |
| ↳ | android.view.View |
| | ↳ | android.view.ViewGroup |
| | | ↳ | android.support.v7.widget.RecyclerView |

| Known Direct Subclasses

HorizontalGridView, VerticalGridView

这个是结构示意图,

官网上面给出了几点提示

  • Adapter: A subclass of [RecyclerView.Adapter](https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html) responsible for providing views that represent items in a data set.
  • Position: The position of a data item within an Adapter.
  • Index: The index of an attached child view as used in a call to [getChildAt(int)](https://developer.android.com/reference/android/view/ViewGroup.html#getChildAt(int)). Contrast with Position.
  • Binding: The process of preparing a child view to display data corresponding to a position within the adapter.
  • Recycle (view): A view previously used to display data for a specific adapter position may be placed in a cache for later reuse to display the same type of data again later. This can drastically improve performance by skipping initial layout inflation or construction.
  • Scrap (view): A child view that has entered into a temporarily detached state during layout. Scrap views may be reused without becoming fully detached from the parent RecyclerView, either unmodified if no rebinding is required or modified by the adapter if the view was considered dirty.
  • Dirty (view): A child view that must be rebound by the adapter before being displayed.

这段介绍是说 RecyclerView 有一个子类 RecyclerView.Adapter 是用来负责提供一个 views 结合来展示 items 的,就是我们使用的 ListView 的 adapter;包括当前的 Item 的 position,

数据的响应等等这些的功能,其实说白了就和 BaseAdapter 的提供的那几个方法一样。RecyclerView 提供了一些公开的设置接口,比如设置横向还是竖向,设置流式布局,分割线的自定义等,这种的话就降低了整个源码的耦合性。可以说比 ListView 这些要好用多了。RecyclerView 可是当 ListView 来使用,也可以当 GridView 来使用。以后再也不用 ListView 和 GridView 了。

采用的也是适配器加观察者的模式来设计的,和 listview 实现的原理是差不多的,只是在布局显示的上面做了一些适配。

用红线标出的这些类和是我们在平时使用中比较多的。

还有一些经常使用的方法:

public void setLayoutManager(LayoutManager layout)

该方法是设置这个横向布局还是竖向布局,网格还是瀑布流布局等这些布局操作

public void setAdapter(Adapter adapter) ;设置适配的数据。

public void addItemDecoration(ItemDecoration decor);设置分割线,这个分割线是通过自己的需求来定义的。

这三个方法是最重要的,也是必须要使用的三个方法。其他的方法没有去详细的分析。

2.使用例子

最简单的使用例子。 普通的列表。

AutoRecycleView

public class AutoRecycleView extends Activity {

@Bind(R.id._id_recyclerview_)
RecyclerView mecyclerview;

private List datas;
private AutoRecycleAdapter mAdapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycle_actiity_view);
ButterKnife.bind(this);
initData();
mecyclerview.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new AutoRecycleAdapter(getApplicationContext(), datas);
mecyclerview.setAdapter(mAdapter );
}

protected void initData() {
    datas = new ArrayList();

for (int i = 0; i < 50; i++) {
datas.add("" + i );
}
}
}

布局文件

xml version="1.0" encoding="utf-8"?> xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
android:id="@+id/id_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />

AutoRecycleViewAdapter 类如下

public class AutoRecycleAdapter extends RecyclerView.Adapter {

private Context context;

private List data; public AutoRecycleAdapter(Context context, List data) {
this.context = context;
this.data = data;
}

@Override

public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
View view = layoutInflater.inflate(R.layout.content_list_item, parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}

@Override

public void onBindViewHolder(MyViewHolder holder, int position) {
holder.name.setText(data.get(position));
}

@Override

public int getItemCount() {
return data.size();
}

class MyViewHolder extends RecyclerView.ViewHolder {
    @Bind(R.id._name_)
    TextView name;   public MyViewHolder(View view) {
        super(view);

ButterKnife.bind(this, view);
}
}
}

item_view 布局文件如下

xml version="1.0" encoding="utf-8"?> xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/green"
android:orientation="vertical">
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:gravity="center"
android:textSize="16sp"
/>

项目采用的是

butterknife 这种注解方式的。方便控件实例化的便捷插件。

运行的结果如下

预期的结果出来了。这个只是最简单是使用,

看到没有这个没有分割线。接下来我们对经常使用一些功能加以详细的分析。

3.RecyclerView.ItemDecoration 分析

ItemDecoration 是 RecyclerView 的内部类,源码如下

/** * 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 static abstract class ItemDecoration {
_/
_ * Draw any appropriate decorations into the Canvas supplied to the RecyclerView. * Any content drawn by this method will be drawn before the item views are drawn, * and will thus appear underneath the views. * * **@param **c Canvas to draw into * **@param **parent RecyclerView this ItemDecoration is drawing into * **@param **state The current state of RecyclerView */ public void onDraw(Canvas c, RecyclerView parent, State state) {
onDraw(c, parent);
}

_/**_  _*_ **_@deprecated_ **_* Override {_**_@link_ **_#__onDraw__(Canvas, RecyclerView, RecyclerView.State)}_  _*/_ @Deprecated

public void onDraw(Canvas c, RecyclerView parent) {
}

_/**_  _* Draw any appropriate decorations into the Canvas supplied to the RecyclerView._  _* Any content drawn by this method will be drawn after the item views are drawn_  _* and will thus appear over the views._  _*_  _*_ **_@param_ **_c_ _Canvas to draw into_  _*_ **_@param_ **_parent_ _RecyclerView this ItemDecoration is drawing into_  _*_ **_@param_ **_state_ _The current state of RecyclerView._  _*/_ public void onDrawOver(Canvas c, RecyclerView parent, State state) {
    onDrawOver(c, parent);

}

_/**_  _*_ **_@deprecated_ **_* Override {_**_@link_ **_#__onDrawOver__(Canvas, RecyclerView, RecyclerView.State)}_  _*/_ @Deprecated

public void onDrawOver(Canvas c, RecyclerView parent) {
}

_/**_  _*_ **_@deprecated_ **_* Use {_**_@link_ **_#__getItemOffsets__(Rect, View, RecyclerView, State)}_  _*/_ @Deprecated

public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
outRect.set(0, 0, 0, 0);
}

_/**_  _* Retrieve any offsets for the given item. Each field of_ ___outRect___ _specifies_  _* the number of pixels that the item view should be inset by, similar to padding or margin._  _* The default implementation sets the bounds of outRect to 0 and returns._  _*_  _*_ __ _* If this ItemDecoration does not affect the positioning of item views, it should set_  _* all four fields of_ ___outRect___ _(left, top, right, bottom) to zero_  _* before returning._  _*_  _*_ __ _* If you need to access Adapter for additional data, you can call_  _* {_**_@link_ **_RecyclerView#__getChildAdapterPosition__(View)} to get the adapter position of the_  _* View._  _*_  _*_ **_@param_ **_outRect_ _Rect to receive the output._  _*_ **_@param_ **_view_ _The child view to decorate_  _*_ **_@param_ **_parent_ _RecyclerView this ItemDecoration is decorating_  _*_ **_@param_ **_state_ _The current state of RecyclerView._  _*/_ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
    getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),

parent);
}
}

这个类是提供了一个专门的来实现分割线的类,这个类现在有三个方法,首先执行的是这个方法 getItemOffsets(Rect outRect,...)这个方法是要这是这个分割线的一个形状是横向还是竖向的。这个方法必须要设置不然不启动作用,如果是水平方向滚动的话,要设置成 outRect.set(0,0,0,2);竖直方向的话采用的是 outRect.set(0,0,2,0); onDraw(Canvas c,RecyclerView recyclerView,State state);这个方法是用来标示绘制具体的效果的。

下面看一个网上找的一个效果

代码如下:

public class AutoRecycleDevider extends RecyclerView.ItemDecoration{
private Paint mPaint;
private Drawable mDivider;
private int mDividerHeight = 2;//分割线高度,默认为 1px
private int mOrientation;//列表的方向:LinearLayoutManager.VERTICAL 或 LinearLayoutManager.HORIZONTAL
private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
/** * 默认分割线:高度为__2px_,颜色为灰色_ * * **@param **context * **@param **orientation 列表方向 */ public AutoRecycleDevider(Context context, int orientation) {
if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
throw new IllegalArgumentException("请输入正确的参数!");
}
mOrientation = orientation; final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
}

_/**_  _*_ _自定义分割线_ _*_  _*_ **_@param_ **_context_ _*_ **_@param_ **_orientation_ _列表方向_ _*_ **_@param_ **_drawableId_ _分割线图片_ _*/_ public AutoRecycleDevider(Context context, int orientation, int drawableId) {
    this(context, orientation);

mDivider = ContextCompat.getDrawable(context, drawableId);
mDividerHeight = mDivider.getIntrinsicHeight();
}

_/**_  _*_ _自定义分割线_ _*_  _*_ **_@param_ **_context_ _*_ **_@param_ **_orientation_ _列表方向_ _*_ **_@param_ **_dividerHeight_ _分割线高度_ _*_ **_@param_ **_dividerColor_ _分割线颜色_ _*/_ public AutoRecycleDevider(Context context, int orientation, int dividerHeight, int dividerColor) {
    this(context, orientation);

mDividerHeight = dividerHeight;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(dividerColor);
mPaint.setStyle(Paint.Style.FILL);
}

//获取分割线尺寸

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(0, 0, 0, mDividerHeight);
}

//绘制分割线

@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
if (mOrientation == LinearLayoutManager.VERTICAL) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}

//绘制横向 item 分割线

private void drawVertical(Canvas canvas, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getMeasuredWidth() - parent.getPaddingRight();
final int childSize = parent.getChildCount();
for (int i = 0; i < childSize; i++) {
final View child = parent.getChildAt(i);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
final int top = child.getBottom() + layoutParams.bottomMargin;
final int bottom = top + mDividerHeight;
if (mDivider != null) {
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
if (mPaint != null) {
canvas.drawRect(left, top, right, bottom, mPaint);
}
}
}

//绘制纵向 item 分割线

private void drawHorizontal(Canvas canvas, RecyclerView parent) { final int top = parent.getPaddingTop();
final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom();
final int childSize = parent.getChildCount();
for (int i = 0; i < childSize; i++) {
final View child = parent.getChildAt(i);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
final int left = child.getRight() + layoutParams.rightMargin;
final int right = left + mDividerHeight;
if (mDivider != null) {
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
if (mPaint != null) {
canvas.drawRect(left, top, right, bottom, mPaint);
}
}
}
}

然后加入下面的代码

// 添加默认分割线:高度为 2px**,颜色为灰色**
mecyclerview.addItemDecoration(new AutoRecycleDevider(getApplicationContext(), LinearLayoutManager.VERTICAL));

运行结果如下

// 添加自定义分割线:可自定义分割线 drawable
mecyclerview.addItemDecoration(new AutoRecycleDevider(
getApplicationContext(), LinearLayoutManager.VERTICAL, R.drawable.divid_bg_drawable));

效果图:

也就是说以后你的列表的分割线想怎么搞就怎么搞了。

4. GridLayoutManager

public class GridLayoutManager
extends [LinearLayoutManager](https://developer.android.com/reference/android/support/v7/widget/LinearLayoutManager.html)

| java.lang.Object |
| ↳ | android.support.v7.widget.RecyclerView.LayoutManager |
| | ↳ | android.support.v7.widget.LinearLayoutManager |
| | | ↳ | android.support.v7.widget.GridLayoutManager |


A [RecyclerView.LayoutManager](https://developer.android.com/reference/android/support/v7/widget/RecyclerView.LayoutManager.html) implementations that lays out items in a grid.

By default, each item occupies 1 span. You can change it by providing a custom [GridLayoutManager.SpanSizeLookup](https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager.SpanSizeLookup.html) instance via [setSpanSizeLookup(SpanSizeLookup)](https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager.html#setSpanSizeLookup(android.support.v7.widget.GridLayoutManager.SpanSizeLookup)).

/**

* Constructor used when layout manager is set in XML by RecyclerView attribute * "layoutManager". If spanCount is not specified in the XML, it defaults to a * single column. * * **@attr **ref android.support.v7.recyclerview.R.styleable#RecyclerView_spanCount */

public GridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); Properties properties = getProperties(context, attrs, defStyleAttr, defStyleRes); setSpanCount(properties.spanCount);}/** * Creates a vertical GridLayoutManager * * **@param **context Current context, will be used to access resources. * **@param spanCount The number of columns in the grid _*/public GridLayoutManager(Context context, int spanCount) { super(context); setSpanCount(spanCount);}/_ * **@param **context Current context, will be used to access resources. * **@param *spanCount The number of columns or rows in the grid * @param orientation Layout orientation. Should be {@link #HORIZONTAL} or {@link_ #VERTICAL}._ * **@param **reverseLayout When set to true, layouts from end to start. _*/_public GridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); setSpanCount(spanCount);}

这个是三个常用的构造函数。

这个是相当于我们使用的 GridView,布局效果,是继承自 LinearLayoutManager 的,提供了获取多少列的方法,以及通过当前的 Item 的 View 来获取对应的位置的方法。

这个类中主要的方法是这些

setSpanCount(int ): void ; getSpanCount() :int 这二个方法是获取或者设置一排有多少个 Item 的方法。

使用的时候如下的代码:

/** * 类名: RecycleViewAnalyise * 功能: * 作者: wanny * 时间: 15:49 2016/6/23 */ public class AutoGridDeciration extends RecyclerView.ItemDecoration {
private Drawable mDivider; public AutoGridDeciration(Context context) {
mDivider = ContextCompat.getDrawable(context, R.drawable.listview_itemdec_bg);
}

@Override

public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
drawHorizonal(c, parent);
drwaVerial(c, parent); }

_/**_  _*_ _水平方向上面的绘制_ _*_  _*_ **_@param_ **_c_ _*_ **_@param_ **_parent_ _*/_ private void drawHorizonal(Canvas c, RecyclerView parent) {
    int childCount = parent.getChildCount();

for (int i = 0; i < childCount; i++) {
final View childView = parent.getChildAt(i);
final RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) childView.getLayoutParams();
final int left = childView.getLeft() - layoutParams.leftMargin;
final int right = childView.getRight() + layoutParams.rightMargin + mDivider.getIntrinsicWidth();
final int top = childView.getBottom() + layoutParams.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}

_/**_  _*_ _竖直方向上面的线断_ _*_  _*_ **_@param_ **_c_ _*_ **_@param_ **_recyclerView_ _*/_ public void drwaVerial(Canvas c, RecyclerView recyclerView) {
    final int childCount = recyclerView.getChildCount();

for (int i = 0; i < childCount; i++) {
final View child = recyclerView.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int top = child.getTop() - params.topMargin;
int left = child.getRight() + params.rightMargin;
int right = left + mDivider.getIntrinsicWidth();
int bottom = child.getBottom() + params.bottomMargin;
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}

//

private boolean isLastColum(RecyclerView parent, View view, int spanCount, int childCount) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) {
int position = ((GridLayoutManager.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();
if ((position + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
{
return true;
}
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int positon = ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();
if ((positon + 1) % childCount == 0) {
return true;
} else {
childCount = childCount - spanCount / childCount;
if (positon >= childCount) {
return true;
}
}
}
return false;
}

_/**_  _* \_  _*_ _判断是不是最后一行,竖直方向的走势_ _*_  _*_ **_@param_ **_parent_ _RecyclerView_ _对象_ _*_ **_@param_ **_view_ _当前的__View__的对象_ _*_ **_@param_ **_spanCount_ _一行或者一列的个数_ _*_ **_@param_ **_childCount_ _adapter__的总的个数。_ _*_ **_@return_ **_*/_ private boolean isLastRaw(RecyclerView parent, View view, int spanCount, int childCount) {
    RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();

//当前 View 的 position;
int position = ((GridLayoutManager.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();
if (layoutManager instanceof GridLayoutManager) {
//取余数
childCount = childCount - childCount % spanCount;
//如何判断当前的 position 是最后一个 position>??
//大于是不可能的但是如果当
if (position >= childCount) {
return true;
}
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int oriation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
//如果是水平方向的话
if (oriation == LinearLayoutManager.VERTICAL) {
childCount = childCount - childCount % spanCount;
// 如果是最后一行,则不需要绘制底部
if (position >= childCount)
return true;
} else {
//表示最后一条数据
if ((position + 1) % childCount == 0) {
return true;
}
}
}
return false;
}

@Override

public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent != null) {
// int position = ((GridLayoutManager.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();
int spanCount = getSpanCountByParent(parent);
int childCount = parent.getAdapter().getItemCount();
if (isLastColum(parent, view, spanCount, childCount)) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else if (isLastRaw(parent, view, spanCount, childCount)) {
outRect.set(0, 0, 2, 0);
} else {
outRect.set(0, 0, 2, mDivider.getIntrinsicHeight());
}

    } else {
        super.getItemOffsets(outRect, view, parent, state);

}

}

_/**_  _*_ _通过__RecyclerView__来获取_ _*_  _*_ **_@param_ **_parent_ _*_ **_@return_ **_*/_ private int getSpanCountByParent(RecyclerView parent) {
    int spanCount = -1;

RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager != null) {
if (layoutManager instanceof GridLayoutManager) {
spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
}
}
return spanCount;
}

}

这个代码的大值逻辑就时添加 item 的分割线。这个其中还包括了瀑布流式控件布局的适配。

由于 Android 的 API 的更新很快,可以说快到有很多的东西,你感觉这个是个新东西,刚开始用着没有一段时间就过时了。所以在 Android 的开发过程对知识的更新是很重要的。

真的是时时刻刻在学新东西。

运行效果如下:

这个就是运行效果。

同样的水平方向滚动的话就添加下面的代码。

mecyclerview.setLayoutManager(new GridLayoutManager(this, 5, LinearLayoutManager.HORIZONTAL, false));

代码只需要改动这一行。

|

public class StaggeredGridLayoutManager
extends [RecyclerView.LayoutManager](https://developer.android.com/reference/android/support/v7/widget/RecyclerView.LayoutManager.html)

| java.lang.Object |
| ↳ | android.support.v7.widget.RecyclerView.LayoutManager |
| | ↳ | android.support.v7.widget.StaggeredGridLayoutManager |

5.StaggeredGridLayoutManager

A LayoutManager that lays out children in a staggered grid formation. It supports horizontal & vertical layout as well as an ability to layout children in reverse.

Staggered grids are likely to have gaps at the edges of the layout. To avoid these gaps, StaggeredGridLayoutManager can offset spans independently or move items between spans. You can control this behavior via [setGapStrategy(int)](https://developer.android.com/reference/android/support/v7/widget/StaggeredGridLayoutManager.html#setGapStrategy(int)).

这个是实现瀑布流的效果,是 RecyclerView.LayoutManger 的子类。用户发的话其实就是差不多一样的效果。

先看代码,

public class AutoStaggleredAdapter extends RecyclerView.Adapter {

private List data;

private Context context;
//因为这个是测试 demo,在正式使用的时候一般是通过显示图片的高度来适应的。这里是通过随机数的方式来搞的。
private ArrayList mHeight;
public AutoStaggleredAdapter(Context context, List data) {
this.context = context;
this.data = data;
mHeight = new ArrayList<>();
for(int i = 0 ; i < 30 ; i ++){
mHeight.add((int)(150 + Math.random() * 250));
}
}

@Override

public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
View view = layoutInflater.inflate(R.layout.item_staggered_home, parent, false);
MyViewHolder myViewHolder = new MyViewHolder(view);
return myViewHolder;
}

@Override

public void onBindViewHolder(MyViewHolder holder, int position) {
//绑定上数据的时候
//可以是复杂的布局,例如淘宝网的宝贝浏览页面。或者有些控件的显示与隐藏。
ViewGroup.LayoutParams layoutParams = holder.idNum.getLayoutParams();
layoutParams.height = mHeight.get(position);
holder.idNum.setLayoutParams(layoutParams);
holder.idNum.setText(data.get(position)); }

@Override

public int getItemCount() {
return data.size();
}

static class MyViewHolder extends RecyclerView.ViewHolder {
    @Bind(R.id._id_num_)
    TextView idNum;

public MyViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
}

}

调用的时候的代码如下:

 mecyclerview.setLayoutManager(new StaggeredGridLayoutManager( 3, LinearLayoutManager._VERTICAL_)); //        mAdapter = new AutoRecycleAdapter(getApplicationContext(), datas);

mAdapter = new AutoStaggleredAdapter(getApplicationContext(),datas);
mecyclerview.setAdapter(mAdapter); // 添加自定义分割线:可自定义分割线 drawable // mecyclerview.addItemDecoration(new AutoRecycleDevider(getApplicationContext(), LinearLayoutManager.VERTICAL)); // mecyclerview.addItemDecoration(new AutoItemDecoration(getApplicationContext(), AutoItemDecoration.VERTICAL)); // 添加自定义分割线:可自定义分割线 drawable
mecyclerview.addItemDecoration(new AutoGridDeciration(this));

运行效果如下:

看到没有是不是挺满意对想要实现的效果。因为这个只是一个简单的 demo 所以没有加逻辑的或者图片的替换等的操作。在项目中结合软件自身的情况来做。

6.总结

对于RecylerView的使用的话了解到这种程度就差不多了,但是你要打算写上拉加载更多或者下拉加载更多的话就的对RecyclerView 做更深入的理解了。RecyclerView替代了传统的ListView 和GridView这二种控件,同时提供一更加开放的布局形式,使控件的耦合性降低了不少。同时提供了分割线的个性化定制。我觉得最重要的一点是提供了一个瀑布流的效果,这个我觉得是最实用的。如果要升入的理解RecyclerView源码的话看下一篇文章。
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    334 引用 • 323 回帖 • 4 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...