详解RecyclerView替换ListView和GridView及实现暴瀑流

前言


在Android中有了ListView,GridView,为什么还需要RecyclerView这样的控件呢?从整体上看,RecyclerView架构提供了一种插拔式体验,它具有高度的解耦,异常的灵活性和更高的效率,它通过提供LayoutManager,ItemDecoration,ItemAnimator实现丰富多样的效果。


使用案例及步骤:


  1.配置Build.Gradle

     使用RecyclerView,我们必须导入support-v7包,在项目build.Gradle配置如下:

    

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    ......
   implementation 'com.android.support:appcompat-v7:27.1.1' 
     implementation 'com.android.support:recyclerview-v7:27.1.1'
    .....
 }

2.使用RecyclerView


recyclerviewList = (RecyclerView) findViewById(R.id.recyclerview_list);
adapter = new RecyclerViewAdapter(this);
listData = new ArrayList<>();
//水平显示
mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true);
getData();
adapter.setListData(listData);
recyclerviewList.setAdapter(adapter);
recyclerviewList.setItemAnimator(new DefaultItemAnimator());
recyclerviewList.setLayoutManager(mLayoutManager);
adapter.notifyDataSetChanged();
与ListView不同的是,需要设置布局管理器用于设置条目的样式排列,可以是VERTICAL排列,也可以是HORIZONTAL排列,这里我们通过代码recyclerviewList.setLayoutManager(new LinearLayoutManager(this));表示条目线性排列(默认是垂直(VERTICAL)排列)。

public void setLayoutManager(LayoutManager layout) {
    if (layout == mLayout) {
        return;
    }
 }

这里的layout参数我们可以不用系统默认的,我们可以自己这样的定义
new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true);
public static final int HORIZONTAL = RecyclerView.HORIZONTAL;
public static final int VERTICAL = RecyclerView.VERTICAL;

在这里LinearLayoutManager源码提供两个方法,第一个默认指定垂直,第二个自己指定方向,代码如下:


1.
/**
 * Creates a vertical LinearLayoutManager
 *
 * @param context Current context, will be used to access resources.
 */
public LinearLayoutManager(Context context) {
    this(context, RecyclerView.DEFAULT_ORIENTATION, false);//默认垂直
}
2.
/**
 * @param context       Current context, will be used to access resources.
 * @param orientation   Layout orientation. Should be {@link #HORIZONTAL} or {@link
 *                      #VERTICAL}.
 * @param reverseLayout When set to true, layouts from end to start.
 */
public LinearLayoutManager(Context context, @RecyclerView.Orientation int orientation,
        boolean reverseLayout) {
    setOrientation(orientation);
    setReverseLayout(reverseLayout);
}

上面我们已经说了RecyclerView两种排列方式,但是我们只写了垂直排列的代码,没有写如何设置水平排列
,但是思路已经说过了,那么接下来我们具体看一水平排列代码设置,如下:

//水平显示
LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
mLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerviewList.setLayoutManager(mLayoutManager);
此外,RecyclerView比ListView设置要复杂一下,比如自定义分割线,设置动画,布局管理器等等。
布局文件 activity_main2.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Main2Activity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerview_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
自定义适配器adapter需要创建class ViewHolderl继承RecyclerView.ViewHolder,
另外,Adapter需要继承RecyclerView.Adapter,重写三个方法,分别是 onCreateViewHolder创建获取布局,
onBindViewHolder绑定布局,getItemCount获取数据大小size,具体代码如下:
 
  
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

    private LayoutInflater inflater;
    private List<String> listData;
    private Context mContext;


    public RecyclerViewAdapter(Context mContext) {
        this.mContext = mContext;
        inflater = LayoutInflater.from(mContext);
    }

    public void setListData(List<String> listData) {
        this.listData = listData;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new ViewHolder(inflater.inflate(R.layout.activity_recyclerview_pattern, parent, false));

    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {

        holder.mTextView.setText(listData.get(position));

    }

    @Override
    public int getItemCount() {
        return listData.size() > 0 ? listData.size() : 0;
    }

    class ViewHolder extends RecyclerView.ViewHolder {

        private TextView mTextView;

        public ViewHolder(View view) {
            super(view);
            mTextView = view.findViewById(R.id.textView2);
        }
    }
}

3.设置分割线

我们通过使用recyclerviewList.addItemDecoration()方法来加入分割线,设置默认分割线,我们自己定义分割线,我们需要来继承RecyclerView.ItemDecoration实现自定义分割线,代码如下:


默认分割线
recyclerviewList.addItemDecoration(new DividerItemDecoration(this,LinearLayoutManager.VERTICAL));
效果图:

自定义分割线
public class ItemDecorationDivider extends RecyclerView.ItemDecoration {

    private Paint mPaint;
    private Drawable mDivider;
    /**
     * 分割线高度,默认为1px
     */
    private int mDividerHeight = 12;
    /**
     * 列表的方向:LinearLayoutManager.VERTICAL或LinearLayoutManager.HORIZONTAL
     */

    /**
     * 分割线缩进值
     */
    private int inset;
    private int mOrientation;
    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};

    /**
     * 默认分割线:高度为2px,颜色为灰色
     *
     * @param context
     * @param orientation 列表方向
     */
    public ItemDecorationDivider(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 ItemDecorationDivider(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 ItemDecorationDivider(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);
    }


    /**
     * 获取分割线尺寸
     *
     * @param outRect
     * @param view
     * @param parent
     * @param state
     */
    @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);
    }

    /**
     * 绘制分割线
     *
     * @param c
     * @param parent
     * @param state
     */
    @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 分割线
     *
     * @param canvas
     * @param parent
     */
    private void drawHorizontal(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 分割线
     *
     * @param canvas
     * @param parent
     */
    private void drawVertical(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);
            }
        }


//        private void drawVertical (Canvas c, RecyclerView parent){
//            final int left = parent.getPaddingLeft();
//            final int right = parent.getWidth() - parent.getPaddingRight();
//            final int childCount = parent.getChildCount(); //最后一个item不画分割线
//            for (int i = 0; i < childCount - 1; i++) {
//                final View child = parent.getChildAt(i);
//                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
//                final int top = child.getBottom() + params.bottomMargin;
//                final int bottom = top + mDivider.getIntrinsicHeight();
//                if (inset > 0) {
//                    c.drawRect(left, top, right, bottom, paint);
//                    mDivider.setBounds(left + inset, top, right - inset, bottom);
//                } else {
//                    mDivider.setBounds(left, top, right, bottom);
//                }
//                mDivider.draw(c);
//            }
//        }
//        private void drawHorizontal (Canvas c, RecyclerView parent){
//            final int top = parent.getPaddingTop();
//            final int bottom = parent.getHeight() - parent.getPaddingBottom();
//            final int childCount = parent.getChildCount();
//            for (int i = 0; i < childCount - 1; i++) {
//                final View child = parent.getChildAt(i);
//                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
//                final int left = child.getRight() + params.rightMargin;
//                final int right = left + mDivider.getIntrinsicHeight();
//                mDivider.setBounds(left, top, right, bottom);
//                mDivider.draw(c);
//            }
//        }
        //由于Divider也有宽高,每一个Item需要向下或者向右偏移
//        @Override
//        public void getItemOffsets (Rect outRect,int itemPosition, RecyclerView parent){
//            if (mOrientation == VERTICAL_LIST) {
//                outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
//            } else {
//                outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
//            }
//        }

    }
}

这里核心的方法是onDraw,它根据传进来的orientation来绘制item是横向还是纵向,也就是drawHorizontal,drawVertial方法,这里注意的是我们一定要在setAdapter之前加入分割线。


水平显示设置颜色
recyclerviewList.addItemDecoration(new ItemDecorationDivider(this,LinearLayoutManager.HORIZONTAL,10,
 ContextCompat.getColor(this,R.color.colorAccent)));

水平显示设置drawable
recyclerviewList.addItemDecoration(new ItemDecorationDivider(this,LinearLayoutManager.HORIZONTAL
,R.drawable.dividershape));

    dividershape.xml如下:

?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#ff9000" />
    <size android:height="5dp" />
</shape>

效果图如下:



4.实现GridView

只需要自定义横向的分割线,然后在代码中设置:


staggeredGridLayoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
recyclerviewList.addItemDecoration(new DividerGridItemDecoration(this,R.drawable.dividershape));
recyclerviewList.setLayoutManager(staggeredGridLayoutManager);
DividerGridItemDecoration:
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration {
    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
    private Drawable mDivider;
    private Paint mPaint;
    private int mDividerHeight = 2;

    public DividerGridItemDecoration(Context context) {
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
    }

    /**
     * 自定义分割线
     * @param context
     * @param drawableId 分割线图片
     */
    public DividerGridItemDecoration(Context context, int drawableId) {
        mDivider = ContextCompat.getDrawable(context, drawableId);
        mDividerHeight = mDivider.getIntrinsicHeight();
    }

    /**
     * 自定义分割线
     * @param context
     * @param dividerHeight 分割线高度
     * @param dividerColor 分割线颜色
     */
    public DividerGridItemDecoration(Context context, int dividerHeight, int dividerColor) {
        mDividerHeight = dividerHeight;
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(context.getResources().getColor(dividerColor));
        mPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        drawHorizontal(c, parent);
        drawVertical(c, parent);
    }

    private int getSpanCount(RecyclerView parent) {
        // 列数
        int spanCount = -1;
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
        }
        return spanCount;
    }

    /**
     * 绘制水平线
     * @param c
     * @param parent
     */
    public void drawHorizontal(Canvas c, RecyclerView parent) {
        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            final int left = child.getLeft() - params.leftMargin;
            final int right = child.getRight() + params.rightMargin + mDividerHeight;
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDividerHeight;
            if (mDivider != null) {
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(c);
            }
            if (mPaint != null) {
                c.drawRect(left, top, right, bottom, mPaint);
            }
        }
    }

    /**
     * 绘制垂直线
     * @param c
     * @param parent
     */

    public void drawVertical(Canvas c, RecyclerView parent) {
        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            final int top = child.getTop() - params.topMargin;
            final int bottom = child.getBottom() + params.bottomMargin;
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDividerHeight;
            if (mDivider != null) {
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(c);
            }
            if (mPaint != null) {
                c.drawRect(left, top, right, bottom, mPaint);
            }
        }
    }

    /**
     * 判断是否是最后一列
     * @param parent
     * @param pos
     * @param spanCount
     * @param childCount
     * @return
     */
    private boolean isLastColum(RecyclerView parent, int pos, int spanCount, int childCount) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            if ((pos + 1) % spanCount == 0)
            // 如果是最后一列,则不需要绘制右边
            {
                return true;
            }
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
            if (orientation == StaggeredGridLayoutManager.VERTICAL) {
                if ((pos + 1) % spanCount == 0) {
                    // 如果是最后一列,则不需要绘制右边
                    return true;
                }
            } else {
                childCount = childCount - childCount % spanCount;
                return pos >= childCount;
            }
        }
        return false;
    }

    /**
     * 判断是否是最后一行
     * @param parent
     * @param pos
     * @param spanCount
     * @param childCount
     * @return
     */
    private boolean isLastRaw(RecyclerView parent, int pos, int spanCount, int childCount) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            childCount = childCount - childCount % spanCount;
            if (pos >= childCount)
            // 如果是最后一行,则不需要绘制底部
            {
                return true;
            }
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
            // StaggeredGridLayoutManager 且纵向滚动
            if (orientation == StaggeredGridLayoutManager.VERTICAL) {
                childCount = childCount - childCount % spanCount; // 如果是最后一行,则不需要绘制底部
                if (pos >= childCount) {
                    return true;
                }
            } else
            // StaggeredGridLayoutManager 且横向滚动
            { // 如果是最后一行,则不需要绘制底部
                if ((pos + 1) % spanCount == 0) {
                    return true;
                }
            }
        }
        return false;
    }
        @Override
        public void getItemOffsets (Rect outRect,int itemPosition, RecyclerView parent){
            int spanCount = getSpanCount(parent);
            int childCount = parent.getAdapter().getItemCount();
            if (isLastRaw(parent, itemPosition, spanCount, childCount))
            // 如果是最后一行,则不需要绘制底部
            {
                outRect.set(0, 0, mDividerHeight, 0);
            } else if (isLastColum(parent, itemPosition, spanCount, childCount))
            // 如果是最后一列,则不需要绘制右边
            {
                outRect.set(0, 0, 0, mDividerHeight);
            } else {
                outRect.set(0, 0, mDividerHeight, mDividerHeight);
            }
        }
    }
实现效果,如下图:


5.实现暴瀑流

  
实现暴瀑流在没有RecyclerView之前是比较困难的,代码还要写一大堆,现在第三方也是很多的,但是Google提供了RecyclerView控件能更容易的实现暴瀑流,
我们没有理由不去用它,因为它更稳定,效率高,自定义能力强。实现暴瀑流其实就是控制每个item的高度的高度就可以了。代码如下:

代码之前不做任何变化只是在如下代码增加设置textView的高度
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {

    if (mHeights.size() <= position) {
        mHeights.add((int) (100 + Math.random() * 300));
    }
    ViewGroup.LayoutParams lp = holder.mTextView.getLayoutParams();
    lp.height = mHeights.get(position);
    holder.mTextView.setLayoutParams(lp);
    holder.mTextView.setText(listData.get(position));

}
效果图如下:

项目结构

 
  

具体代码:

1.Activity
public class Main2Activity extends AppCompatActivity {

    private RecyclerView recyclerviewList;
    private RecyclerViewAdapter adapter;
    private List<String> listData;
    private LinearLayoutManager mLayoutManager;
    private StaggeredGridLayoutManager staggeredGridLayoutManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.activity_main2);
        initView();
    }

    private void initView() {
        recyclerviewList = (RecyclerView) findViewById(R.id.recyclerview_list);
        adapter = new RecyclerViewAdapter(this);
        listData = new ArrayList<>();
        //水平显示
//        mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        staggeredGridLayoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
        getData();
        adapter.setListData(listData);
//        recyclerviewList.addItemDecoration(new ItemDecorationDivider(this,LinearLayoutManager.HORIZONTAL,R.drawable.dividershape));
        recyclerviewList.addItemDecoration(new DividerGridItemDecoration(this,R.drawable.dividershape));

        recyclerviewList.setAdapter(adapter);
        recyclerviewList.setItemAnimator(new DefaultItemAnimator());
        recyclerviewList.setLayoutManager(staggeredGridLayoutManager);
        adapter.notifyDataSetChanged();
         }

    /**
     * 获取数据
     */
    private void getData() {
        for (int i = 0; i < 20; i++) {
            listData.add("测试" + i);
        }
    }
}

2.activity_main2.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Main2Activity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerview_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
3.adapter

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

    private Context mContext;
    private LayoutInflater inflater;
    private List<String> listData;
    private List<Integer> mHeights;


    public RecyclerViewAdapter(Context mContext) {
        this.mContext = mContext;
        inflater = LayoutInflater.from(mContext);
        mHeights = new ArrayList<>();
    }

    public void setListData(List<String> listData) {
        this.listData = listData;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new ViewHolder(inflater.inflate(R.layout.activity_recyclerview_pattern, parent, false));

    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {

        if (mHeights.size() <= position) {
            mHeights.add((int) (100 + Math.random() * 300));
        }
        ViewGroup.LayoutParams lp = holder.mTextView.getLayoutParams();
        lp.height = mHeights.get(position);
        holder.mTextView.setLayoutParams(lp);
        holder.mTextView.setText(listData.get(position));


    }

    @Override
    public int getItemCount() {
        return listData.size() > 0 ? listData.size() : 0;
    }

    class ViewHolder extends RecyclerView.ViewHolder {

        private TextView mTextView;

        public ViewHolder(View view) {
            super(view);
            mTextView = view.findViewById(R.id.textView2);
        }
    }
}
4.activity_recyclerview_pattern.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context=".Main2Activity">


    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:layout_weight="1"
        android:gravity="center" />
</LinearLayout>

 
 

RecyclerView替换ListView和GridView及实现暴瀑流

 
 

 
 


猜你喜欢

转载自blog.csdn.net/u014133119/article/details/80825055