Android RecycleView使用详解

一、RecycleView简要介绍

RecycleView是support-v7包中的新组件,是一个强大的滑动组件。相比于ListView和GridView具有很多让开发者喜欢的优点,如:数据绑定,Item的创建和View的回收复用机制等。但RecycleView更加高级灵活,当我们数据因为用户事件或者网络事件发生改变的时候也能很好的进行显示。RecycleView最主要的特点就是复用。

二、RecycleView与ListView区别

RecycleView是ListView的升级版,与经典的ListView相比,同样具有item的回收复用功能。

1.RecycleView封装了ViewHolder的回收复用,标准化了ViewHolder,编写Adapter面向的是ViewHolder,而不是View,高度解耦,复用的逻辑被封装,给编写代码带来更大的方便。

2.RecycleView提供了一种插拔式的体验,高度解耦,异常灵活,为了来控制item的显示,RecycleView针对一个Item的显示专门抽取了相应的类,使其扩展性非常强。

3.可以控制Item增减动画,可以通过ItemAnimation来进行控制。当然,RecycleView有其自己默认的实现方式。

4.使用LayoutManager来确定每一个item的排列方式。

5.在使用RecycleView之前,需要继承RecycleView.Adapter适配,将数据与每个item进行绑定。

6.利用LayoutManager确定每一个item如何摆放、何时展示与隐藏。或者回收复用View的时候,LayoutManager回想适配器请求新的数据来替换以前的数据,该机制避免了创建过多的View和频繁调用Id方法。

三、Recycle基本用法

1.在项目gradle下添加依赖。

compile ‘com.android.support:recyclerview-v7:25.0.1‘

2.实现RecycleView布局。

<android.support.v7.widget.RecyclerView
    android:id="@+id/id_recyclerview"
    android:divider="#ffff0000"
    android:dividerHeight="10dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

3.设置布局管理器。布局主要有三种实现方式,本文采用流式布局进行解析。

mRecyclerView.setLayoutManager(new LinearLayoutManager(this));    //线性布局
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 4));     //网格
mRecyclerView.setLayoutManager(new
        StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL));     //流式布局

4.设置Adapter与ViewHolder进行事件绑定。

@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
    ViewGroup.LayoutParams lp = holder.tv.getLayoutParams();
    if(position != 0 && position < mDatas.size()){
        lp.height = mHeights.get(position);
        holder.tv.setLayoutParams(lp);
    }
    holder.tv.setText(mDatas.get(position));

}

5.setAdapter与设置分割线、Item动画。

mAdapter = new HomeAdapter(this, mDatas);
        mAdapter.setOnItemClickListener(this);
        mRecyclerView.setAdapter(mAdapter);
        //设置默认分割线
//        mRecyclerView.addItemDecoration(new DividerItemDecoration(this,
//                DividerItemDecoration.VERTICAL));
        mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this));

        //设置Item动画
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());

6.初始化数据。

private void initListData() {
    mDatas = new ArrayList<String>();
    for (int i = ‘A‘; i <= ‘z‘; i++) {
        mDatas.add("" + (char) i);
    }
}

7.设置Item点击事件(增加Item)。RecycleView没有像ListView一样给我提供一个onItemClickListener内置监听器,当我们点击item触发事件的时候会回调相关方法,不过我们可以改造Adapter以达到我们的目的。

holder.itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        int pos = holder.getLayoutPosition();
        listener.OnItemClick(holder.itemView, pos);
        addData(pos);
    }
});
public void addData(int position)
{
    mDatas.add(position, "Insert One");
    notifyItemInserted(position);
}

8.设置长按点击事件(移除Item)。同7一样,主要是使用RecycleView方法添加和删除数据。与ListView不同的是,ListView在数据发生变化的时候采用的是notifyDatasetChange方法刷新数据,但RecycleView采用更高级的方法notifyItemInserted(position)和notifyItemRemoved(position)来进行添加和删除的数据刷新。

holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View view) {
        int pos = holder.getLayoutPosition();
        listener.onItemLongClick(holder.itemView, pos);
        removeData(pos);
        return false;
    }
});
public void removeData(int position)
{
    mDatas.remove(position);
    notifyItemRemoved(position);
}

9.分割线的封装。

package example.com.demo_recycleview;

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.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;

public class DividerGridItemDecoration extends RecyclerView.ItemDecoration {

    private static final int[] ATTRS = new int[] { android.R.attr.listDivider };
    private Drawable mDivider;

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

    @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;
    }

    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
                    + mDivider.getIntrinsicWidth();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    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 + mDivider.getIntrinsicWidth();

            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    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;
                if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
                    return true;
            }
        }
        return false;
    }

    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, mDivider.getIntrinsicWidth(), 0);
        } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边
        {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else
        {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(),
                    mDivider.getIntrinsicHeight());
        }
    }
}

四、效果展示

 
           

五、源码下载

地址:http://download.csdn.net/detail/u012721519/9743570

Good luck!

Write by Jimmy.li

时间: 2024-10-05 15:26:44

Android RecycleView使用详解的相关文章

android屏幕适配详解

android屏幕适配详解 官方地址:http://developer.android.com/guide/practices/screens_support.html 一.关于布局适配建议 1.不要使用绝对布局 2.尽量使用match_parent 而不是fill_parent . 3.能够使用权重的地方尽量使用权重(android:layout_weight) 4.如果是纯色背景,尽量使用android的shape 自定义. 5.如果需要在特定分辨率下适配,可以在res目录上新建layout

Android 四大组件 详解

[置顶] Android四大组件详解 分类: Android四大组件2013-02-09 16:23 19411人阅读 评论(13) 收藏 举报 Android开发 注:本文主要来自网易的一个博主的文章,经过阅读,总结,故留下文章在此 Android四大基本组件介绍与生命周期 Android四大基本组件分别是Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器. 一:了解四大基本组件 Activity : 应用程序中,一个

Android权限Permission详解

android.permission.EXPAND_STATUS_BAR 允许一个程序扩展收缩在状态栏,Android开发网提示应该是一个类似Windows Mobile中的托盘程序 android.permission.FACTORY_TEST 作为一个工厂测试程序,运行在root用户 android.permission.INSTALL_PACKAGES 允许一个程序安装packages android.permission.INTERNAL_SYSTEM_WINDOW 允许打开窗口使用系统

Android进阶——Preference详解之Preference系的基本应用(三)

引言 前面一篇文章Android进阶--Preference详解之Preference系的基本应用和管理(二)介绍了二级Preference的使用和特点,接下来进入系统给我提供的底级Preference的使用CheckBox选择项CheckBoxPreference.EditText编辑对话框EditTextPreference.列表选择ListPreference.多项选择MultiSelectListPreference. 开关选择SwitchPreference的应用和管理.以期大家能在学

Android SlidingMenu 使用详解

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/36677279 很多APP都有侧滑菜单的功能,部分APP左右都是侧滑菜单~SlidingMenu 这个开源项目可以很好帮助我们实现侧滑功能,如果对SlidingMenu 还不是很了解的童鞋,可以参考下本篇博客.将侧滑菜单引入项目的方式很多中,本博客先通过例子介绍各种引入方式,然后给大家展示个实例:主布局ViewPager,左右各一个侧滑菜单的用法,差不多已经能满足大部分应用的需求

Android中Context详解 ---- 你所不知道的Context

转载至 :http://blog.csdn.net/qinjuning 前言:本文是我读<Android内核剖析>第7章 后形成的读书笔记 ,在此向欲了解Android框架的书籍推荐此书. 大家好,  今天给大家介绍下我们在应用开发中最熟悉而陌生的朋友-----Context类 ,说它熟悉,是应为我们在开发中 时刻的在与它打交道,例如:Service.BroadcastReceiver.Activity等都会利用到Context的相关方法 : 说它陌生,完全是 因为我们真正的不懂Context

Android相机开发详解(一)

Android相机开发详解(一) 请支持原创,尊重原创,转载请注明出处:http://blog.csdn.net/kangweijian(来自kangweijian的csdn博客) Android相机开发能够实现打开相机,前后摄像头切换,摄像预览,保存图片,浏览已拍照图片等相机功能. Android相机开发详解(一)主要实现打开相机,摄像预览,前后置摄像头切换,保存图片等四个功能. Android相机开发详解(二)主要实现翻页浏览相片,触控缩放浏览图片,删除图片,发送图片等四个功能. Andro

Android中Context详解 ---- 你所不知道的Context (转载)

Android中Context详解 ---- 你所不知道的Context (转载) http://blog.csdn.net/qinjuning 大家好,  今天给大家介绍下我们在应用开发中最熟悉而陌生的朋友-----Context类 ,说它熟悉,是应为我们在开发中 时刻的在与它打交道,例如:Service.BroadcastReceiver.Activity等都会利用到Context的相关方法 : 说它陌生,完全是 因为我们真正的不懂Context的原理.类结构关系.一个简单的问题是,一个应用

Android之canvas详解

首先说一下canvas类: Class Overview The Canvas class holds the "draw" calls. To draw something, you need 4 basic components: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect, Path, t