安卓v7支持包下的ListView替代品————RecyclerView

 

RecyclerView这个控件也出来很久了,相信大家也学习的差不多了,如果还没学习的,或许我可以带领大家体验一把这个艺术般的控件。

据官方介绍,该控件是属于之间用的非常多的ListView和GridView的替代品,既然能替代用的如此普遍的它们,这自然有其该有的优势。

1)相对于ListView而言RecyclerView的优势体现在:

①封装了之前ListView的优化,封装了之前ViewHolder的复用,这样在自定义适配器的时候我们面向的不再是View,而是一个ViewHolder.

②提供了插板式的体验,高度解耦,异常灵活,针对每一项的显示抽取出了相应的类来控制每一个item的显示。若想实现网格视图或者瀑布流或者横向的ListView都可以通过制定不一样的LayoutManager来实现高大上的效果,这样就可以针对自己的业务逻辑随意发挥了。

③现在的RecyclerView对增删也有了动画的加入,并且你还可以自定义这些动画。

④对于Adaper适配器,现在刷新也增加了相应的方法,虽然之前的notifyDataSetChanged()同样可以实现这样的效果,但是每次刷新整个界面在数据多的时候必然会大大影响用户体验。所以Adapter增加了更新数据的方法notifyItemInserted和notifyItemRemoved,这样就可以在增删数据的时候只刷新被操作的Item,而且还加入了高大上的动画效果呢。

2)基本用法:

相信描述了这么多,你一定对这个神奇的控件迫不及待想尝试一波了。要用到这个RecyclerView很简单,首先在Gradle中添加支持包:

1
compile 'com.android.support:recyclerview-v7:24.0.0'

下面就先来一个简单的用法,首先来Activity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.example.nanchen.recyclerviewdemo;
 
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Toast;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
 
public class MainActivity extends AppCompatActivity implements MyAdapter.OnRecyclerItemClickListener {
 
    private MyAdapter adapter;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.main_recycler);
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
//            list.add(String.format(Locale.CHINA, "第%03d条数据%s", i, i % 2 == 0 ? "" : "-----------------------"));
            list.add(String.format(Locale.CHINA, "第%03d条数据", i));
        }
        adapter = new MyAdapter(this, list);
        adapter.setOnRecyclerItemClickListener(this);
        recyclerView.setAdapter(adapter);
 
        DefaultItemAnimator animator = new DefaultItemAnimator();
        animator.setRemoveDuration(1000);
        recyclerView.setItemAnimator(animator);
        //recyclerView.addItemDecoration(new MyDividerItemDecoration(this,MyDividerItemDecoration.VERTICAL_LIST));
 
        //最后一个参数是反转布局一定是false,为true的时候为逆向显示,在聊天记录中可能会有使用
        //这个东西在显示后才会加载,不会像ScollView一样一次性加载导致内存溢出
        LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(layoutManager);
 
        //        GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3);
        //        gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
        //            @Override
        //            public int getSpanSize(int position) {
        //                if (position == 0){
        //                    return 3;
        //                }
        //                return 1;
        //            }
        //        });
        //        recyclerView.setLayoutManager(gridLayoutManager);
 
//        StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
//        recyclerView.setLayoutManager(staggeredGridLayoutManager);
    }
 
    @Override
    public void OnRecyclerItemClick(RecyclerView parent, View view, int position, String data) {
        Toast.makeText(this, data, Toast.LENGTH_SHORT).show();
        adapter.remove(position);
    }
}

  在上面的Activity代码中,可见,我们需要自己指定LayoutManager,代码中用的是LinearLayoutMagener,你可以试试其他的。

再看看Adapter,有一个对大多数人来说很悲催的是,我们的ListView中一定会有的点击事件,而RecyclerView并没有提供这样的方法,这些点击事件都是需要我们自己学的,我这里Adapter就简单的实现了下,点击就会删除该Item。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package com.example.nanchen.recyclerviewdemo;
 
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
 
import java.util.List;
 
/**
 * 自定义RecyclerView的Adapter
 * Created by 南尘 on 16-7-15.
 */
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> implements View.OnClickListener {
 
    private Context context;
    private List<String> list;
    private OnRecyclerItemClickListener listener;
    private RecyclerView recyclerView;
 
    public void setOnRecyclerItemClickListener(OnRecyclerItemClickListener listener) {
        this.listener = listener;
    }
 
    public MyAdapter(Context context, List<String> list) {
        this.context = context;
        this.list = list;
    }
 
    //在为RecyclerView提供数据的时候调用
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        this.recyclerView = recyclerView;
    }
 
    @Override
    public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
        super.onDetachedFromRecyclerView(recyclerView);
        this.recyclerView = null;
    }
 
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.item,parent,false);
        view.setOnClickListener(this);
        return new ViewHolder(view);
    }
 
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.text.setText(list.get(position));
    }
 
    @Override
    public int getItemCount() {
        return list.size();
    }
 
    @Override
    public void onClick(View v) {
        if (recyclerView != null && listener != null){
            int position = recyclerView.getChildAdapterPosition(v);
            listener.OnRecyclerItemClick(recyclerView,v,position,list.get(position));
        }
    }
 
    /**
     * 删除指定数据
     * @param position 数据位置
     */
    public void remove(int position){
        list.remove(position);
//        notifyDataSetChanged();
        notifyItemRemoved(position);//这样就只会删除这一条数据,而不会一直刷
 
    }
 
    /**
     * 插入数据
     * @param position 插入位置
     * @param data 插入的数据
     */
    public void insert(int position,String data){
        list.add(position,data);
        notifyItemInserted(position);
 
    }
 
    public static class ViewHolder extends RecyclerView.ViewHolder{
 
        private final TextView text;
 
        public ViewHolder(View itemView) {
            super(itemView);
            text = (TextView) itemView.findViewById(R.id.item_text);
        }
    }
 
 
    /**
     * 自定义RecyclerView的点击事件
     */
    interface OnRecyclerItemClickListener{
        void OnRecyclerItemClick(RecyclerView parent,View view,int position,String data);
    }
 
}

  继承这个Adapter需要指定一个ViewHolder的泛型,当然这个ViewHolder通常是由我们作为一个静态类自己写的。其他这个就像我们之前ListView中的BaseAdapter一样。

自己还可以实现其他的点击事件。

下面看下Xml,第一个是主布局,第二个是每一个项的布局,我这里就简单只实现一个TextView了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.nanchen.recyclerviewdemo.MainActivity">
 
    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/main_recycler"/>
 
</RelativeLayout>

  

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:orientation="vertical">
 
    <TextView
        android:id="@+id/item_text"
        android:textSize="30sp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

  这样运行出来你估计就会看到没有分割线,那么分割线怎么弄呢,看下文档,需要我们自己去写,这个网上有很多。

上一个我看到过很多次的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package com.example.nanchen.recyclerviewdemo;
 
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.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
 
/**
 * Created by 南尘 on 16-7-15.
 */
public class MyDividerItemDecoration extends RecyclerView.ItemDecoration {
    private static final int[] ATTRS = new int[]{
            android.R.attr. listDivider
    };
 
    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
 
    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
 
    private Drawable mDivider;
 
    private int mOrientation;
 
    public MyDividerItemDecoration(Context context, int orientation) {
        final TypedArray a = context.obtainStyledAttributes(ATTRS );
        mDivider = a.getDrawable(0);
        a.recycle();
        setOrientation(orientation);
    }
 
    public void setOrientation( int orientation) {
        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
            throw new IllegalArgumentException( "invalid orientation");
        }
        mOrientation = orientation;
    }
 
    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            drawVertical(c, parent);
        else {
            drawHorizontal(c, parent);
        }
    }
 
 
    public void drawVertical(Canvas c, RecyclerView parent) {
        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();
 
        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.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }
 
    public 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; 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);
        }
    }
 
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if (mOrientation == VERTICAL_LIST) {
            outRect.set(000, mDivider.getIntrinsicHeight());
        }else{
            outRect.set(00, mDivider.getIntrinsicWidth(), 0);
        }
    }
}

  这样使用的是系统的分割线。

这样在Style中可以自己更改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<resources>
 
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
         
        <item name="android:listDivider">@drawable/divider_bg</item>
    </style>
 
 
</resources>

  自定义一个Drawble

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle" >
 
    <gradient
        android:centerColor="#ff00ff00"
        android:endColor="#ff0000ff"
        android:startColor="#ffff0000"
        android:type="linear" />
    <size android:height="4dp"/>
 
</shape>

  别忘了去把之前我给的MainActivity.java中把分割线那句代码解去注释。

1
2
//增加分割线
recyclerView.addItemDecoration(new MyDividerItemDecoration(this,MyDividerItemDecoration.VERTICAL_LIST));

最后上一波简单的运行图吧。

android listview 替代品recyclerview详解的更多相关文章

  1. Android listview 侧滑 SwipeListView 详解 实现微信,QQ等滑动删除效果

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/28508769 今天看别人项目,看到别人使用了SwipeListView,Goog ...

  2. ANDROID L——Material Design详解(UI控件)

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! Android L: Google已经确认Android L就是Android Lolli ...

  3. Xamarin android CardView的使用详解

    android 5.0新增加的一个控件CardView,在support v7兼容包中,意思就是卡片View,虽然可以设置阴影,圆角等等样式,但是我们也可以自己写出来,谷歌工程师之所以出这个,肯定是帮 ...

  4. 《Android NFC 开发实战详解 》简介+源码+样章+勘误ING

    <Android NFC 开发实战详解>简介+源码+样章+勘误ING SkySeraph Mar. 14th  2014 Email:skyseraph00@163.com 更多精彩请直接 ...

  5. Android开发之InstanceState详解

    Android开发之InstanceState详解   本文介绍Android中关于Activity的两个神秘方法:onSaveInstanceState() 和 onRestoreInstanceS ...

  6. android bundle存放数据详解

    转载自:android bundle存放数据详解 正如大家所知道,Activity之间传递数据,是将数据存放在Intent或者Bundle中 例如: 将数据存放倒Intent中传递: 将数据放到Bun ...

  7. Cordova 打包 Android release app 过程详解

    Cordova 打包 Android release app 过程详解 时间 -- :: SegmentFault 原文 https://segmentfault.com/a/119000000517 ...

  8. Android中Service(服务)详解

    http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...

  9. 给 Android 开发者的 RxJava 详解

    我从去年开始使用 RxJava ,到现在一年多了.今年加入了 Flipboard 后,看到 Flipboard 的 Android 项目也在使用 RxJava ,并且使用的场景越来越多 .而最近这几个 ...

随机推荐

  1. 14.8.2 Role of the .frm File for InnoDB Tables InnoDB 表得到 .frm文件的作用

    14.8.2 Role of the .frm File for InnoDB Tables InnoDB 表得到 .frm文件的作用 Vsftp:/data01/mysql/zjzc# ls -lt ...

  2. git日志的查看与修改

    1.命令行中查看日志 git log 默认是显示所有的日志信息,之前出来的界面显示的日志,很少. 最后发现,只需要使用键盘上向下键↓,就可以继续浏览更多的日志 空格键,可以翻页浏览日志. 向左←  向 ...

  3. RHCS集群理论暨最佳实践

    RHCS集群理论暨 最佳实践 什么是集群?     集群是一组(>2)相互独立的,通过高速网络互联的计算机组成的集合.群集一般可以分为科学集群,负载均衡集群,高可用性集群三大类.     科学集 ...

  4. HDU 5927 Auxiliary Set 【DFS+树】(2016CCPC东北地区大学生程序设计竞赛)

    Auxiliary Set Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tot ...

  5. 培训机构出来的iOS学员怎么了?

    事件回放 前几天在 iOS 开发群里看到有人贴了一个 v2ex 上的帖子(地址:https://www.v2ex.com/t/244437 ) ,大概说收到了 1000 多份某培训机构出来的学员简历. ...

  6. 265行JavaScript代码的第一人称3D H5游戏Demo【个人总结1】

    本文目的是分解前面的代码.其实,它得逻辑很清楚,只是对于我这种只是用过 Canvas 画线(用过 Fabric.js Canvas库)的人来说,这个还是很复杂的.我研究这个背景天空也是搞了一天,下面就 ...

  7. MyEclipse中web服务器的三种配置方式

    初学Javaweb开发的人们都会遇到一个问题,就是服务器环境的搭建配置问题.下面介绍三种服务器的搭建方式. 直接修改server.xml文件 当你写了一个web应用程序(jsp/servlet),想通 ...

  8. MT9v024总结

    S1: A typical READ or WRITE sequence begins by the master sending a start bit. After thestart bit, t ...

  9. tomcat在linux中的启动和查看相关信息

      打开终端cd /java/tomcat#执行bin/startup.sh #启动tomcatbin/shutdown.sh #停止tomcattail -f logs/catalina.out # ...

  10. sencha touch 框架的几种核心脚本文件之间的区别

    sencha-touch-debug.js      供开发时用sencha-touch.js   供发布时用sencha-touch-all.js All     供不能使用SDK构建应用程序时,将 ...