美文网首页
Android5.0 RecyclerView的使用

Android5.0 RecyclerView的使用

作者: 上善若水Ryder | 来源:发表于2016-03-21 14:10 被阅读0次

    RecylerView简介

    RecylerView是一个高级的ListView。可以很好的维护大数据集的滚动和显示。
    

    RecylerView位置

    包名:android.support.v7.widget.RecyclerView
    文件地址有两个
    1: android-sdk/extras/android/m2repository/com/android/support/recyclerview-v7
    2:android-sdk/extras/android/support/v7/recyclerview
    

    RecylerView引用

    Android Studio

    dependencies {
      compile 'com.android.support:recyclerview-v7:21.0.0'
    }
    

    Eclipse

    1.在android-sdk/extras/android/support/v7/recyclerview目录下面有libs,里面有jar包,引用此jar包。
    2.在android-sdk/extras/android/m2repository/com/android/support/recyclerview-v7目录下根据版本号21.0.0目录可以找到一个名为recyclerview-v7-21.0.0.aar的文件。解压此文件里面有classes.jar,引用此jar包。
    
    针对找不到目录,可以打开Android SDK Manager把最新的资源更新下来即可。
    

    在此推荐使用Android Studio开发Android项目

    为什么要使用RecyclerView

    RecyclerView适用于无法在一个屏幕范围内展现格式一样的数据时,需要用多行或多列来展示。

    比如,当用户滑动使当前一个可视的Item滑出屏幕,这个Item的视图将会被回收并在一个新Item进入可视范围后重新被使用。

    可回收利用View是个很实用的功能,它不仅可以减少CPU不断Inflate View的开销,而且可以节省缓存View的内存开销。

    ListView具备这样的机制,但是当使用ListView时,显示,回收等功能是紧密耦合在一起的。

    RecyclerView不负责显示工作。和ListView不一样的是,RecyclerView不再负责Item的摆放等显示方面的功能。所有和布局、绘制等方面的工作Google都其拆分成不同的类进行管理。所以我们可以自定义各种各样满足定制需求的的功能类。

    RecylerView类的说明

    涉及到的类

    Adapter(android.support.v7.widget.RecyclerView.Adapter)
    ViewHolder(android.support.v7.widget.RecyclerView.ViewHolder)
    LayoutManager(android.support.v7.widget.RecyclerView.LayoutManager)
    

    Adapter
    适配器,跟ListView有关的Adapter是不一样,此Adapter为RecylerView特有。作为一个抽象类,有以下几个抽象方法。

    public static abstract class Adapter<VH extends ViewHolder> {
        public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
        public abstract void onBindViewHolder(VH holder, int position);
        public abstract int getItemCount();
        ...
    }
    

    1. onCreateViewHolder

    直接创建一种可复用的VH或者根据ViewType创建多种VH。

    2. onBindViewHolder

    数据和VH通过位置position绑定

    3. getItemCount

    返回有多少条数据

    4. ViewHolder

    同样是一个抽象类,我们通过继承此类实现view的封装。

    5. LayoutManager

    布局管理器,RecylerView中数据显示布局方式。目前v7包种提供了三种模式,分别是LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager。

    LinearLayoutManager
    线性布局,通过方向VERTICAL和HORIZONTAL可以实现垂直和水平的效果。默认为VERTICAL垂直方向。
    通过此布局可以实现ListView的效果。垂直方向为普通的ListView显示效果,水平方向即是水平滑动的ListView。
    
    GridLayoutManager
    网格布局,继承于LinearLayoutManager,可以指定有几行和方向。
    通过此布局可以实现GridView的效果,同样有垂直方向和水平方向。
    
    StaggeredGridLayoutManager
    交错网格布局,类似于网格布局,但每个格子的高度或者长度可以不一样。俗称的瀑布流效果,同样有垂直方向和水平方向。
    

    实例代码

    引入的包

    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile 'com.android.support:appcompat-v7:21.0.0'
        compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.3'
        compile 'com.android.support:recyclerview-v7:21.0.0'
        compile 'org.roboguice:roboguice:2.0'
        compile 'com.android.support:palette-v7:21.0.0'
    }
    

    MainActivity.java

    package com.cienet.android;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.support.v4.widget.SwipeRefreshLayout;
    import android.support.v7.widget.GridLayoutManager;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.StaggeredGridLayoutManager;
    
    import com.cienet.android.adapter.MyAdapter;
    
    import roboguice.activity.RoboFragmentActivity;
    import roboguice.inject.InjectView;
    
    public class MainActivity extends RoboFragmentActivity {
    
        @InjectView(R.id.recyclerView)
        private RecyclerView recyclerView;
    
        @InjectView(R.id.swipeLayout)
        private SwipeRefreshLayout swipeLayout;
    
        private MyAdapter adapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            adapter = new MyAdapter(this, getPicUrls());
    
            useLinearLayoutManager();
    //      useGridLayoutManager();
    //      useStaggeredGridLayoutManager();
    
            recyclerView.setAdapter(adapter);
    
            // 模拟下拉刷新
            swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
                @Override
                public void onRefresh() {
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            swipeLayout.setRefreshing(false);
                            adapter.notifyDataSetChanged();
                        }
                    }, 2000);
                }
            });
        }
    
        /**
         * 使用线性布局管理器
         * @return
         */
        private void useLinearLayoutManager() {
            // 创建线性布局管理器
            LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
            // 设置显示布局的方向,默认方向是垂直
    //        linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
            // 设置布局管理器
            recyclerView.setLayoutManager(linearLayoutManager);
        }
    
        /**
         * 使用网格布局管理器
         * @return
         */
        private void useGridLayoutManager() {
            // 创建网格布局管理器
            GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
            // 设置显示布局的方向,默认方向是垂直
    //        gridLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
            // 设置布局管理器
            recyclerView.setLayoutManager(gridLayoutManager);
        }
    
        /**
         * 使用交错网格布局管理器
         * @return
         */
        private void useStaggeredGridLayoutManager() {
            // 创建交错网格布局管理器
            StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, LinearLayoutManager.VERTICAL);
            // 设置布局管理器
            recyclerView.setLayoutManager(staggeredGridLayoutManager);
        }
    
        private String[] getPicUrls() {
            String[] picUrls = new String[]{
                    "http://img0.hao123.com/data/1_2d6066fea769896573b01478c2312832_510",
                    "http://img4.hao123.com/data/1_dd84959fa7910d741d0f4cc9dec79bdd_510",
                    "http://img6.hao123.com/data/1_72b86760cbcf0a9251e4c5d28127d3f6_510",
                    "http://img3.hao123.com/data/1_ae18d3a1b65a0194a8f5fa2c76f3f8a7_0",
                    "http://img5.hao123.com/data/1_bc6ef28f063aa1c0d72daed48a18554a_0",
                    "http://img.hao123.com/data/1_62333db73d9fa2fe2a1db6f26edab9f3_0",
                    "http://img.hao123.com/data/1_0c4f1dc3daab007063fac855c9825ca5_0",
                    "http://img6.hao123.com/data/1_22699180ce1bfef7db27c205a3b9cda2_0",
                    "http://img4.hao123.com/data/1_758d06615bb089bcc979aa974442720a_0",
                    "http://img.hao123.com/data/1_bf80a0aa0901e1a52ba2cd03c164511e_0"
            };
    
            return picUrls;
        }
    }
    

    MyAdapter.java

    package com.cienet.android.adapter;
    
    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.ImageView;
    import android.widget.TextView;
    
    import com.cienet.android.R;
    import com.nostra13.universalimageloader.core.ImageLoader;
    
    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
        private String[] picUrls;
    
        public MyAdapter(Context context, String[] picUrls) {
            this.picUrls = picUrls;
        }
    
        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
            // 加载数据item的布局,生成VH返回
            if (null == viewGroup.getTag()) {
                View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_vertical, viewGroup, false);
    //        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_horizontal, viewGroup, false);
    //        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_gridlayout, viewGroup, false);
    //        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_staggered_gridlayout, viewGroup, false);
                viewGroup.setTag(view);
                return new MyViewHolder(view);
            } else {
                return new MyViewHolder((View) viewGroup.getTag());
            }
        }
    
        @Override
        public void onBindViewHolder(MyViewHolder viewHolder, int i) {
            // 数据绑定
            ImageLoader.getInstance().displayImage(picUrls[i], viewHolder.picImageView);
            viewHolder.picUrl.setText(picUrls[i]);
        }
    
        @Override
        public int getItemCount() {
            // 返回数据有多少条
            if (null == picUrls) {
                return 0;
            }
            return picUrls.length;
        }
    
        // 可复用的VH
        public class MyViewHolder extends RecyclerView.ViewHolder {
            public ImageView picImageView;
            public TextView picUrl;
    
            public MyViewHolder(View itemView) {
                super(itemView);
                picImageView = (ImageView) itemView.findViewById(R.id.imavPic);
                picUrl = (TextView) itemView.findViewById(R.id.tvUrl);
            }
        }
    }
    

    activity_main.xml

    <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"
        android:background="@android:color/holo_red_dark"
        tools:context=".MainActivity">
    
        <android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/swipeLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <android.support.v7.widget.RecyclerView
                android:id="@+id/recyclerView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scrollbars="vertical" />
        </android.support.v4.widget.SwipeRefreshLayout>
    </RelativeLayout>
    

    item_vertical.xml

    <?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="match_parent"
        android:layout_margin="5dp"
        android:orientation="vertical">
    
        <!-- 垂直时候使用的ImageView控件-->
        <ImageView
            android:id="@+id/imavPic"
            android:layout_width="wrap_content"
            android:layout_height="150dp"
            android:scaleType="centerCrop" />
    
        <TextView
            android:id="@+id/tvUrl"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:lines="2" />
    </LinearLayout>
    

    item_horizontal.xml

    <?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="match_parent"
        android:layout_margin="5dp"
        android:orientation="vertical">
    
        <!-- 水平时候使用的ImageView控件-->
        <ImageView
            android:id="@+id/imavPic"
            android:layout_width="150dp"
            android:layout_height="150dp"
            android:scaleType="centerCrop" />
    
        <TextView
            android:id="@+id/tvUrl"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:lines="2" />
    </LinearLayout>
    

    item_gridlayout.xml

    <?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="match_parent"
        android:layout_margin="5dp"
        android:orientation="vertical">
    
        <ImageView
            android:id="@+id/imavPic"
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:scaleType="centerCrop" />
    
        <TextView
            android:id="@+id/tvUrl"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:lines="2" />
    </LinearLayout>
    

    item_staggered_gridlayout.xml

    <?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="match_parent"
        android:layout_margin="5dp"
        android:orientation="vertical">
    
    
        <ImageView
            android:id="@+id/imavPic"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scaleType="centerCrop" />
    
        <TextView
            android:id="@+id/tvUrl"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    

    自己运行验证结果,这里就不上图了。

    与ListView的相同与不同

    其实官方文档说,RecyclerView是ListView的豪华增强版。它主要包含以下几处新的特性,
    如ViewHolder,ItemDecorator,LayoutManager,SmothScroller以及增加或删除item时item动画等。
    并且官方推荐我们采用RecyclerView来取代ListView。

    1. ViewHolder

    ViewHolder是用来保存视图引用的类,无论是ListView亦或是RecyclerView。只不过在ListView中,
    ViewHolder需要自己来定义,且这只是一种推荐的使用方式,不使用当然也可以,这不是必须的。
    只不过不使用ViewHolder的话,ListView每次getView的时候都会调用findViewById(int),
    这将导致ListView性能展示迟缓。而在RecyclerView中使用RecyclerView.ViewHolder则变成了必须,
    尽管实现起来稍显复杂,但它却解决了ListView面临的上述不使用自定义ViewHolder时所面临的问题。
    RecyclerView.ViewHolder被BaseAdapter使用,以将posiiton绑定到上面
    (可以通过API查看 RecyclerView.ViewHolder#getPosition() 方法)。

    2. LayoutManager

    ListView只能在垂直方向上滚动,Android API没有提供ListView在水平方向上面滚动的支持。
    或许有多种方式实现水平滑动,但是ListView并不是设计来做这件事情的。而RecyclerView相较于
    ListView,在滚动上面的功能扩展了许多。它可以支持多种类型列表的展示要求。

    3. ItemAnimator

    Android API中,删除或添加item时,item是无法产生动画效果的。相比较于ListView,
    RecyclerView.ItemAnimator则被提供用于在RecyclerView添加、删除或移动item时处理动画效果。
    同时,不想自定义ItemAnimator,可以使用已有的 DefaultItemAnimator 。

    4. Adapter

    ListView的Adapter中,getView是最重要的方法,它将视图跟position绑定起来。
    同时我们也能够通过registerDataObserver在Adapter中注册一个观察者。RecyclerView也有这个特性,
    RecyclerView.AdapterDataObserver就是这个观察者。ListView有三个Adapter的默认实现,
    分别是ArrayAdapter、CursorAdapter和SimpleCursorAdapter。然而,RecyclerView的Adapter则
    拥有除了内置的内DB游标和ArrayList的支持之外的所有功能。 RecyclerView.Adapter 的实现的,
    我们必须采取措施将数据提供给Adapter,正如BaseAdapter对ListView所做的那样。

    5. ItemDecoration

    在ListView中如果我们想要在item之间添加间隔符,我们只需要在布局文件中对ListView添加如下属性即可:

    1 android:divider="@android:color/transparent"
    2 android:dividerHeight="5dp"
    

    RecyclerView在默认情况下并不在item之间展示间隔符。这个问题增加了我们的负担。如果你想要添加间隔符,
    你必须使用RecyclerView.ItemDecoration类来实现。或者,可以参考应用官方示例中的 DividerItemDecoration.java文件。

    6. OnItemTouchListener

    ListView通过AdapterView.OnItemClickListener接口来探测点击事件。而RecyclerView则通过
    RecyclerView.OnItemTouchListener接口来探测触摸事件。它虽然增加了实现的难度,但是却给予我们拦截触摸事件
    更多的控制权限。

    Others

    ListView可以设置选择模式,并添加MultiChoiceModeListener,如下所示:

    listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
    listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            ...
        }
            
        public void onItemCheckedStateChanged(ActionMode mode, int position,
                                                      long id, boolean checked) {
            ...
        }
                
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            switch (item.getItemId()) {
                case R.id.menu_item_delete_crime:
                    CrimeAdapter adapter = (CrimeAdapter)getListAdapter();
                    CrimeLab crimeLab = CrimeLab.get(getActivity());
                    for (int i = adapter.getCount() - 1; i >= 0; i--) {
                        if (getListView().isItemChecked(i)) {
                            crimeLab.deleteCrime(adapter.getItem(i));
                        }
                    }
                    mode.finish();
                    adapter.notifyDataSetChanged();
                    return true;
                default:
                    return false;
            }
                
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) 
            ... 
        }
        
        public void onDestroyActionMode(ActionMode mode) {
            ...
        }
    });
    

    而RecyclerView则没有此功能。

    总之,通过比较我们可以发现,RecyclerView充满了大量的自定义功能,它可以用于实现复杂的列表或网格,但实现起来稍显得复杂。

    相关文章

      网友评论

          本文标题:Android5.0 RecyclerView的使用

          本文链接:https://www.haomeiwen.com/subject/grpklttx.html