1. 程式人生 > >Android RecyclerView 使用完全解析

Android RecyclerView 使用完全解析

概述

RecyclerView出現已經有一段時間了,相信大家肯定不陌生了,大家可以通過匯入support-v7對其進行使用。 
據官方的介紹,該控制元件用於在有限的視窗中展示大量資料集,其實這樣功能的控制元件我們並不陌生,例如:ListView、GridView。

那麼有了ListView、GridView為什麼還需要RecyclerView這樣的控制元件呢?整體上看RecyclerView架構,提供了一種插拔式的體驗,高度的解耦,異常的靈活,通過設定它提供的不同LayoutManager,ItemDecoration , ItemAnimator實現令人瞠目的效果。

  • 你想要控制其顯示的方式,請通過佈局管理器LayoutManager
  • 你想要控制Item間的間隔(可繪製),請通過ItemDecoration
  • 你想要控制Item增刪的動畫,請通過ItemAnimator
  • 你想要控制點選、長按事件,請自己寫(擦,這點尼瑪。)

基本使用

鑑於我們對於ListView的使用特別的熟悉,對比下RecyclerView的使用程式碼:

mRecyclerView = findView(R.id.id_recyclerview);
//設定佈局管理器
mRecyclerView.setLayoutManager(layout);
//設定adapter
mRecyclerView.setAdapter(adapter)
//設定Item增加、移除動畫
mRecyclerView.setItemAnimator(new DefaultItemAnimator()); //新增分割線 mRecyclerView.addItemDecoration(new DividerItemDecoration( getActivity(), DividerItemDecoration.HORIZONTAL_LIST));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

ok,相比較於ListView的程式碼,ListView可能只需要去設定一個adapter就能正常使用了。而RecyclerView基本需要上面一系列的步驟,那麼為什麼會新增這麼多的步驟呢?

那麼就必須解釋下RecyclerView的這個名字了,從它類名上看,RecyclerView代表的意義是,我只管Recycler View,也就是說RecyclerView只管回收與複用View,其他的你可以自己去設定。可以看出其高度的解耦,給予你充分的定製自由(所以你才可以輕鬆的通過這個控制元件實現ListView,GirdView,瀑布流等效果)。

Just like ListView

  • Activity
package com.zhy.sample.demo_recyclerview;

import java.util.ArrayList;
import java.util.List;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class HomeActivity extends ActionBarActivity
{

    private RecyclerView mRecyclerView;
    private List<String> mDatas;
    private HomeAdapter mAdapter;

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

        initData();
        mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mRecyclerView.setAdapter(mAdapter = new HomeAdapter());

    }

    protected void initData()
    {
        mDatas = new ArrayList<String>();
        for (int i = 'A'; i < 'z'; i++)
        {
            mDatas.add("" + (char) i);
        }
    }

    class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
    {

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
        {
            MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
                    HomeActivity.this).inflate(R.layout.item_home, parent,
                    false));
            return holder;
        }

        @Override
        public void onBindViewHolder(MyViewHolder holder, int position)
        {
            holder.tv.setText(mDatas.get(position));
        }

        @Override
        public int getItemCount()
        {
            return mDatas.size();
        }

        class MyViewHolder extends ViewHolder
        {

            TextView tv;

            public MyViewHolder(View view)
            {
                super(view);
                tv = (TextView) view.findViewById(R.id.id_num);
            }
        }
    }

}
  • 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
  • 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
  • Activity的佈局檔案
<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.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" />

</RelativeLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • Item的佈局檔案
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="#44ff0000"
    android:layout_height="wrap_content" >

    <TextView
        android:id="@+id/id_num"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:text="1" />
</FrameLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

這麼看起來用法與ListView的程式碼基本一致哈~~ 
看下效果圖:

看起來好醜,Item間應該有個分割線,當你去找時,你會發現RecyclerView並沒有支援divider這樣的屬性。那麼怎麼辦,你可以給Item的佈局去設定margin,當然了這種方式不夠優雅,我們文章開始說了,我們可以自由的去定製它,當然我們的分割線也是可以定製的。

ItemDecoration

我們可以通過該方法新增分割線: 
mRecyclerView.addItemDecoration() 
該方法的引數為RecyclerView.ItemDecoration,該類為抽象類,官方目前並沒有提供預設的實現類(我覺得最好能提供幾個)。 
該類的原始碼:

public static abstract class ItemDecoration {

public void onDraw(Canvas c, RecyclerView parent, State state) {
            onDraw(c, parent);
 }


public void onDrawOver(Canvas c, RecyclerView parent, State state) {
            onDrawOver(c, parent);
 }

public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
            getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
                    parent);
}

@Deprecated
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
            outRect.set(0, 0, 0, 0);
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

當我們呼叫mRecyclerView.addItemDecoration()方法新增decoration的時候,RecyclerView在繪製的時候,去會繪製decorator,即呼叫該類的onDraw和onDrawOver方法,

  • onDraw方法先於drawChildren
  • onDrawOver在drawChildren之後,一般我們選擇複寫其中一個即可。
  • getItemOffsets 可以通過outRect.set()為每個Item設定一定的偏移量,主要用於繪製Decorator。

接下來我們看一個RecyclerView.ItemDecoration的實現類,該類很好的實現了RecyclerView新增分割線(當使用LayoutManager為LinearLayoutManager時)。 
該類參考自:DividerItemDecoration


package com.zhy.sample.demo_recyclerview;

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * limitations under the License.
 */

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.support.v7.widget.RecyclerView.State;
import android.util.Log;
import android.view.View;


/**
 * This class is from the v7 samples of the Android SDK. It's not by me!
 * <p/>
 * See the license above for details.
 */
public class DividerItemDecoration 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 DividerItemDecoration(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) {
        Log.v("recyclerview - itemdecoration", "onDraw()");

        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);
            android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext());
            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, int itemPosition, RecyclerView parent) {
        if (mOrientation == VERTICAL_LIST) {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        }
    }
}
  • 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
  • 相關推薦

    Android Service完全解析,關於服務你所需知道的一切(下)

    並且 無法 數據類型 界面 其它 wid logcat listen 程序崩潰 文章轉載至:http://blog.csdn.net/guolin_blog/article/details/9797169 這是郭霖寫的.......就是寫 "第一行代碼"的那個厲害人物,大

    Android OkHttp完全解析 是時候來了解OkHttp了

    JD rect eat serve 功能 sessions 文件名 -h 適合 一、概述 最近在群裏聽到各種討論okhttp的話題,可見okhttp的口碑相當好了。再加上Google貌似在6.0版本裏面刪除了HttpClient相關API,對於這個行為不做評價。為了更好的在

    Android Service完全解析,關於服務你所需知道的一切(上)(筆記)

    參考原文:Android Service完全解析,關於服務你所需知道的一切(上) Service的基本用法 然後新建一個MyService繼承自Service,並重寫父類的onCreate()、onStartCommand()和onDestroy()方法, 可以看到,在Sta

    Android ConstraintLayout完全解析和效能分析(章節二)

    這篇文章是基於Android ConstraintLayout完全解析和效能分析(章節一)基礎上對屬性的深入詳解,如果之前對Android ConstraintLayout不瞭解或者不會使用的,請檢視章節一的內容。若是有一定的瞭解,想深入對ConstraintLayout屬性的瞭解及效能的分

    Android ConstraintLayout完全解析和效能分析(章節一)

    一、說在前面的話 在這裡預祝大家2019年:豬事順利,青春永豬,豬圓玉潤,豬籠入水—八面來財 對於這個已經出現了兩年的新佈局ConstraintLayout,之前只是作為知識瞭解並未在真正的使用它,今天讓我們來從幾個方面解讀ConstraintLayout並對它的效能做細緻化分析。

    Android HandlerThread 完全解析

                         1、概述話說最近股市變動不變,也成了熱火朝天的話題。不知道大家有沒有考慮做個實時更新股市資料的app呢?假設我們要做一個股市資料實時更新的app,我們可以在網上找個第三方的股市資料介面,然後在我們的app中每隔1分鐘(合適的時間)去更新資料,然後更新我們的UI即可。當

    Android ViewDragHelper完全解析 自定義ViewGroup神器

                         一、概述在自定義ViewGroup中,很多效果都包含使用者手指去拖動其內部的某個View(eg:側滑選單等),針對具體的需要去寫好onInterceptTouchEvent和onTouchEvent這兩個方法是一件很不容易的事,需要自己去處理:多手指的處理、加速度檢測

    Android Volley完全解析 四 ,帶你從原始碼的角度理解Volley

                    經過前三篇文章的學習,Volley的用法我們已經掌握的差不多了,但是對於Volley的工作原理,恐怕有很多朋友還不是很清楚。因此,本篇文章中我們就來一起閱讀一下Volley的原始碼,將它的工作流程整體地梳理一遍。同時,這也是Volley系列的最後一篇文章了。其實,Volley的

    Android感測器完全解析

                         什麼是感測器維基百科是這樣定義的:感測器是一種物理裝置或生物器官,能夠探測、感受外界的訊號、物理條件(如光、熱、溼度)或化學組成(如煙霧),並將探知的資訊傳遞給其他裝置或器官。常用感測器介紹與用法Android平臺支援三個大類的感測器Motion sensors(運動

    Android Webp 完全解析 快來縮小apk的大小吧

                         一、概述最近專案準備嘗試使用webp來縮小包的體積,於是抽空對相關知識進行了調研和學習。至於什麼是webp,使用webp有什麼好處我就不贅述了,具體可以參考騰訊isux上的這篇文章WebP 探尋之路,大致瞭解下就ok了。入手大致需要考慮以下幾個問題:如何將現有的jpe

    Android Fragment完全解析,關於碎片你所需知道的一切

    我們都知道,Android上的介面展示都是通過Activity實現的,Activity實在是太常用了,我相信大家都已經非常熟悉了,這裡就不再贅述。但是Activity也有它的侷限性,同樣的介面在手機上顯示可能很好看,在平板上就未必了,因為平板的螢幕非常大,手機的介面放在平板上

    Android Scroller完全解析,關於Scroller你所需知道的一切

    轉載請註明出處:http://blog.csdn.net/guolin_blog/article/details/48719871 2016大家新年好!這是今年的第一篇文章,那麼應CSDN工作人員的建議,為了能給大家帶來更好的閱讀體驗,我也是將部落格換成了寬屏

    Android Service完全解析,關於服務你所需知道的一切(上)

    相信大多數朋友對Service這個名詞都不會陌生,沒錯,一個老練的Android程式設計師如果連Service都沒聽說過的話,那確實也太遜了。Service作為Android四大元件之一,在每一個應用程式中都扮演著非常重要的角色。它主要用於在後臺處理一些耗時的邏輯,或者去執行

    Android TagFlowLayout完全解析 一款針對Tag的佈局(針對多個條目的單選操作)

    目錄(?)[+] 一、概述 本文之前,先提一下關於上篇博文的100多萬訪問量請無視,博文被刷,我也很鬱悶,本來想把那個文章放到草稿箱,結果放不進去,還把日期弄更新了,實屬無奈。 因為本身FlowLayout本身的預期是提供一種新的佈局的方式,但是呢,在實際的開發中

    Android DiskLruCache完全解析,硬碟快取的最佳方案

    概述記得在很早之前,我有寫過一篇文章Android高效載入大圖、多圖解決方案,有效避免程式OOM,這篇文章是翻譯自Android Doc的,其中防止多圖OOM的核心解決思路就是使用LruCache技術。但LruCache只是管理了記憶體中圖片的儲存與釋放,如果圖片從記憶體中被

    Android Volley完全解析(一),初識Volley的基本用法

    1. Volley簡介我們平時在開發Android應用的時候不可避免地都需要用到網路技術,而多數情況下應用程式都會使用HTTP協議來發送和接收網路資料。Android系統中主要提供了兩種方式來進行HTTP通訊,HttpURLConnection和HttpClient,幾乎在任

    Android Volley完全解析(三),定製自己的Request

    原文連結  http://blog.csdn.net/guolin_blog/article/details/17612763 經過前面兩篇文章的學習,我們已經掌握了Volley各種Request的使用方法,包括StringRequest、JsonRequest

    Android-volley完全解析

    1. Volley簡介 我們平時在開發Android應用的時候不可避免地都需要用到網路技術,而多數情況下應用程式都會使用HTTP協議來發送和接收網路資料。Android系統中主要提供了兩種方式來進行HTTP通訊,HttpURLConnection和HttpClie

    Android ActionBar完全解析,使用官方推薦的最佳導航欄(下)

    本篇文章主要內容來自於Android Doc,我翻譯之後又做了些加工,英文好的朋友也可以直接去讀原文。限於篇幅的原因,在上篇文章中我們只學習了ActionBar基礎部分的知識,那麼本篇文章我們將接著上一章的內容繼續學習,探究一下ActionBar更加高階的知識。如果你還沒有看

    Android xUtils3完全解析

    轉自:http://www.w2bc.com/article/156732 1.先來認識一下xUtils3 1)xUtils3簡介 xUtils是基於Afinal開發的目前功能比較完善的一個Android開源框架,最近又釋出了xUtil3.0,在增加新功能的同時又