[置顶] RecyclerView的通用适配器的高级使用

前言

博主由于项目中频繁的使用了V7包中的RecyclerView来代替ListView的列表展示,所以抽空基于ListView的通用适配器的原理,给RecyclerView也写了一个通用适配器主要支持以下功能:

1.支持item的点击事件,在多布局的情况下可以指定生效的itemType

2.支持item中的控件的点击事件(博主觉得具有创新性),在多布局的情况下可以指定生效的itemType

3.支持添加和移除头部(博主没有写添加尾部的方法,其实和添加头部的方法是类似的,如果你有需要就自己参照着改下吧)

4.支持多布局(其实这个并不是博主写的功能,而是自带的,下面会陈述)

以上的功能都是通用适配器完成的,对RecyclerView本身没有做任何的更改

那么博主就先带大家来看看是如何使用的吧,看看他是如果提高我们的开发效率的!


Xml布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.yoursecondworld.recyclerviewdemo.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    
</RelativeLayout>

Number One(一个竖直的简单的列表,显示人名)

public class MainActivity extends AppCompatActivity {

    //展示数据的列表
    private RecyclerView rv = null;

    //需要展示的数据
    private List<String> data = new ArrayList<String>();

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


        //展示的数据造假
        for(int i = 0; i < 100; i++) {
            data.add("item:" + i);
        }

        //寻找控件
        rv = (RecyclerView) findViewById(R.id.rv);

        //创建一个线性的布局管理器并设置
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        rv.setLayoutManager(layoutManager);

        CommonRecyclerViewAdapter<String> adapter = new CommonRecyclerViewAdapter<String>(this, data) {
            @Override
            public void convert(CommonRecyclerViewHolder h, String entity, int position) {
                h.setText(android.R.id.text1, entity);
            }

            //返回item布局的id
            @Override
            public int getLayoutViewId(int viewType) {
                return android.R.layout.simple_list_item_1;
            }
        };

        //设置适配器
        rv.setAdapter(adapter);

    }
}

你可以看到适配器是通过内部类new出来的,因为代码量比较少所以这样子写了,你们在项目中最好创建一个类哦

代码很简单,就是让RecyclerView竖直的展示了数据,item的布局暂时使用了系统的

效果


可以看到显示没有一点问题,那么我要实现条目的点击怎么办?

实现item的点击效果

adapter.setOnRecyclerViewItemClickListener(new CommonRecyclerViewAdapter.OnRecyclerViewItemClickListener() {
        @Override
        public void onItemClick(View v, int position) {
               Toast.makeText(MainActivity.this, "你点击了第" + position + "个item", Toast.LENGTH_SHORT).show();
        }
});
是不是和Listview的条目监听是一样一样的?换个方法名称而已嘛对不对

点击item效果


可以看到,点击事件生效

多布局demo

由于显示的需要,我们需要一个实体对象

entity

public class DemoEntity {

    //如果有这个说明需要使用tag条目
    private String tag;

    //如果有这个说明要使用item条目
    private String name;

    public DemoEntity(String tag, String name) {
        this.tag = tag;
        this.name = name;
    }

    public String getTag() {
        return tag;
    }

    public void setTag(String tag) {
        this.tag = tag;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

注释中可以看出,如果有tag属性,那么没有name属性

既然是多布局,那么两个及以上的布局,这里以两个布局为例子

xml(TagItem)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tv_tag"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#0000FF"
        android:textSize="24dp" />

</RelativeLayout>

xml(NameItem)

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

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:textSize="16dp" />

</RelativeLayout>

然后我们在适配器中需要多一个方法了,先看代码

修改后的Activity代码

public class MainActivity extends AppCompatActivity {

    //展示数据的列表
    private RecyclerView rv = null;

    //需要展示的数据
    private List<DemoEntity> data = new ArrayList<DemoEntity>();

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


        //展示的数据造假
        data.add(new DemoEntity("A", null));
        data.add(new DemoEntity(null, "阿大"));
        data.add(new DemoEntity(null, "阿姨"));
        data.add(new DemoEntity("C", null));
        data.add(new DemoEntity(null, "陈旭金"));

        //寻找控件
        rv = (RecyclerView) findViewById(R.id.rv);

        //创建一个线性的布局管理器并设置
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        rv.setLayoutManager(layoutManager);

        CommonRecyclerViewAdapter<DemoEntity> adapter = new CommonRecyclerViewAdapter<DemoEntity>(this, data) {

            @Override
            public void convert(CommonRecyclerViewHolder h, DemoEntity entity, int position) {
                int itemViewType = getItemViewType(position);
                if (itemViewType == 1) {
                    h.setText(R.id.tv_tag, entity.getTag());
                } else {
                    h.setText(R.id.tv_name, entity.getName());
                }
            }

            //返回item布局的id
            @Override
            public int getLayoutViewId(int viewType) {
                if (viewType == 1) {
                    return R.layout.tag;
                } else {
                    return R.layout.item;
                }
            }

            //默认是返回0,所以你可以定义返回1表示使用tag,2表示使用item,
            //这里返回的值将在getLayoutViewId方法中出现
            @Override
            public int getItemType(int position) {
                //根据实体对象中的属性来返回view的类型
                DemoEntity demoEntity = data.get(position);
                if (demoEntity.getTag() != null) { //如果是tag,应该返回1
                    return 1;
                } else {
                    return 2;
                }
            }
        };

        //设置适配器
        rv.setAdapter(adapter);

        adapter.setOnRecyclerViewItemClickListener(new CommonRecyclerViewAdapter.OnRecyclerViewItemClickListener() {
            @Override
            public void onItemClick(View v, int position) {
                Toast.makeText(MainActivity.this, "你点击了第" + position + "个item", Toast.LENGTH_SHORT).show();
            }
        });

    }
}

我们看到多了一个getItemType方法,用来返回下标为position的时候的viewItem的标识,这个可以随你自己定义,上面就是1表示Tag,2表示name

然后我们的getLayoutViewId方法就不再是单纯的返回同一个布局啦,就要根据刚刚的标识返回对应的xml的id啦

同理,在convert方法中也得判断后再进行对item中的控件赋值啦!代码不难,博主也做了注释

看效果


数据的数量比较少就不能滑动了,你自己数据弄多点就行啦

针对多布局的item点击事件,有时候我们需要只要名称的item的点击作用生效就行了,所以adapter中也提供了相应的方法

public void setOnRecyclerViewItemClickListener(OnRecyclerViewItemClickListener onRecyclerViewItemClickListener, int... itemTypes)

adapter.setOnRecyclerViewItemClickListener(new CommonRecyclerViewAdapter.OnRecyclerViewItemClickListener() {
        @Override
        public void onItemClick(View v, int position) {
             Toast.makeText(MultiLayoutActivity.this, "你点击了第" + position + "个item", Toast.LENGTH_SHORT).show();
        }
}, 2);

细心一点可以看到,设置监听的最后我跟上了一个2,那么这个2是什么用呢?还记得上面的多布局,我们的2表示显示名称的item,所以这里的2就是指点击事件只对显示名称的item起作用,而这个2也是你自己在上面自定义的,所以要学会变通

看效果!


可以看我我无论如何点击蓝色的字母,这里都没有起作用,这个设计博主觉得挺6的,你说呢?

演示监听item内部控件的点击事件

首先我们在显示名称的item中添加一个按钮
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="16dp"
        android:text="name"
        android:textSize="16dp" />

    <!--新添加一个按钮,在文本的右边-->
    <Button
        android:id="@+id/bt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/tv_name"
        android:text="点我" />

</RelativeLayout>

就添加了一个按钮

然后呢,我们在Activity去监听这个item中的按钮!方法为:

public void setOnViewInItemClickListener(OnViewInItemClickListener onViewInItemClickListener, int... viewIdsInItem)
viewIdsInItem是一个整形数组,就是你想监听的item中的控件的id

用法:

//添加item中按钮控件监听
adapter.setOnViewInItemClickListener(new CommonRecyclerViewAdapter.OnViewInItemClickListener() {
        @Override
        public void onViewInItemClick(View v, int position) {
            DemoEntity demoEntity = data.get(position);
            Toast.makeText(MultiLayoutActivity.this, "你点击了第" + position + "个item,name = " + demoEntity.getName(), Toast.LENGTH_SHORT).show();
        }
}, R.id.bt);

为了可以滑动,数据我造假多一点

        data.add(new DemoEntity("A", null));
        data.add(new DemoEntity(null, "阿大"));
        data.add(new DemoEntity(null, "阿姨1"));
        data.add(new DemoEntity(null, "阿姨2"));
        data.add(new DemoEntity(null, "阿姨3"));
        data.add(new DemoEntity(null, "阿姨4"));
        data.add(new DemoEntity("C", null));
        data.add(new DemoEntity(null, "陈旭金1"));
        data.add(new DemoEntity(null, "陈旭金2"));
        data.add(new DemoEntity(null, "陈旭金3"));
        data.add(new DemoEntity(null, "陈旭金4"));

效果


可以看到item中的按钮被成功点击!并且显示出对应的名称和点击item是有点区别的

演示添加头部试图

头部xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FF0000">


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="我是头部"
            android:textColor="#FFFFFF"
            android:textSize="40dp" />

    </RelativeLayout>


</RelativeLayout>
然后我们添加一个头部

adapter.addHeaderView(View.inflate(this, R.layout.header, null));

效果


demo和通用适配器源码下载

https://github.com/xiaojinzi123/android-demos/tree/master/RecyclerViewDemo

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。
按照下面的步骤走,就可以打包成功,我不说各种原因,只讲操作步骤: 简单粗暴!!! 首先你得有一个苹果开发者账号。要是没有,就自己申请一个。 注意: 在创建app IDs 还有描述文件的时候,需要添加的是发布版本,就是ad hoc里面的版本,而不是简单的开发版本。如下图:(证书与描述文件都需要发布版本的) 可以先忽略,一会在创建证书的时候再看 1.创建一个ipaDemo工程。 2.打开苹果开发者中心。 网址 :https://developer.apple.com/membercenter 3.打开这个网址

RecyclerView详细介绍&使用。 - 2016-07-15 18:07:28

主菜RecyclerView 简介 RecyclerView 是 Android 5.0 提供的新控件,已经用了很长时间了,但是一直没有时间去仔细的梳理一下。现在有时间了,决定来整理下。 官方文档中是这样介绍的: A flexible view for providing a limited window into a large data set. RecyclerView比listview更先进更灵活,对于很多的视图它就是一个容器,可以有效的重用和滚动。当数据动态变化的时候请使用它。 专业术语: Ad
所有程序开发遇到的问题都离不开查阅文档,首先将安卓中文完整版文档免费共享给大家 如需下载点击此下载链接:http://download.csdn.net/detail/kzg_ip/9576142 1.控件焦点问题 一些通知在开发过程中,会发现EditText这个控件如果处理不当会出现自动获取焦点的情况,也就是当你打开你的应用是,界面会自动跳出软件盘,那么经过本人多次调试,最有效的方法就是在EditText的父容器中加上下面两句代码便可以去除焦点。其他控件去除焦点也可用此方法。 方法一 将EditText
如果你仔细观察原始的动画,会发现有8个分开动画的不同元素。 黑色箭头和“Dance Club”文本 “Ministry of Fun”文本 “Add a Song”按钮 五首歌对应的五行 这8个元素(或元素组,因为箭头和“Dance Club”文本是一起动画的)是通过不同的开始时间递进进入视图的,这就是我们要在动画中获取的非常酷的波浪感效果。 首先我们整理一下计划。我需要做的是分开添加这些元素到界面上,这样我就可以分开动画它们了。如果这是一个真实的app,有着真实流入的数据,这个界面最可能是一个 UITa
引言 前面一篇文章 Android进阶——Preference详解之初识Preference及Preference系(一) 简单描述下了Preference的家族构成和基本知识,相信对于Preference早已不会陌生,肯定也跃跃欲试了吧,这篇文章就给大家总结下Preference、PreferenceActivity、PreferenceGroup、RingtonePreference的普通应用和管理,还有通过一些测试来验证一些机制和原理。 一、PreferenceActivity 1、Preferen
平时工作中,经常有这样的需求,就是从RIL层一直到APP,添加一个新接口给APP调用,方便系统APP或者第三方APP通过这个接口获取或者改变modem中某些的值、状态等。 基于高通平台,有三种方式去实现这种接口: 扩展ImsSenderRxr,依赖ImsService来实现。 扩展RILJ,依赖Phone进程来实现。 结合1和2,依赖Phone进程来实现。 其中,第一种方式最简单,第二种次之,第三种最复杂;但是每种方式各自有各自的限制条件以及适用范围。 本 文 来 自 http://blog.csdn.n

iOS-Quartz2D画图 - 2016-07-15 17:07:55

常说温故而知新,时隔这么久再次看这些基础内容仍然很兴奋!把敲的代码分享出来,希望能对读者提供一丁点启发 /** * 裁剪圆形图片 */ -( void )circleIcon{ UIImage *image = [UIImage imageNamed:@ "baby" ]; UIGraphicsBeginImageContext(image.size); UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake( 0 ,
转载请标明出处: 一片枫叶的专栏 上一篇文章中我们讲解了如何在android studio中进行单元测试。实际开发过程中有一些功能性的需求,比如测试工具类,测试数据存储等测试工作,如果还是通过重复执行apk文件的编译,安装,运行等会浪费大量的时间,而这些功能与android的开发环境无太大的关系,我们完全可以使用单元测试来执行。android studio中默认是支持进行单元测试的,并提供了获取Context等系统对象的API,我们可以通过其系统提供的API获取Context等对象,进而测试相应的功能。
简介 虽然目前市面上有一些不错的加密相册App,但不是内置广告,就是对上传的张数有所限制。本文介绍了一个加密相册的制作过程,该加密相册将包括多密码(输入不同的密码即可访问不同的空间,可掩人耳目)、WiFi传图、照片文件加密等功能。目前项目和文章会同时前进,项目的源代码可以在github上下载。 点击前往GitHub 概述 上一篇文章 主要介绍了相册管理界面的设计与实现。本文主要介绍图片浏览器设计的技术细节。 图片浏览器设计 说明 之前尝试了使用 MWPhotoBrowser 来处理多图浏览与查看原图,但有
Android Studio官方文档之添加URL和App索引支持 本文由nyk翻译,jkYishon审校。 Android Studio可以帮你在App中添加对URLs,app索引,搜索功能的支持。这些功能可以帮你推动更多的流量到你的App、发现App中最被常用的内容,使用户更容易发现已安装App中内容,并以此来吸引新用户。 典型的工作流程 用Android Studio添加对URL支持,App索引,搜索功能到你的App中: 添加Intent过滤器和处理传入Intent的代码 关联网站和App 添加App