1. 程式人生 > >RecyclerView全攻略進階優化

RecyclerView全攻略進階優化

        Google 釋出的Material Design支援庫,支援庫應該直接用V4提升到V7了,引入了RecycleView。RecylcerView從去年5.0開始釋出好一陣子,這貨目前能相容到API 7,直接繼承自Viewgroup,比ListView更為輕量,使用得當的話,完全可以替代ListView/GridView。本文將基於RecyclerView實現ListView/GridView的一些基礎特性,和下拉重新整理,載入更多,PinnedHeader等一些高階特性。

       以前也用eclipse寫過recyclerView這樣的東西,但是現在用android stuido寫的話更加方便,再也不要去拷貝jar去libs裡面,也不會出現方法找不到的問題,木前呢我的用到了api23,然後我們開始寫咯。

1、新增引用

 在Android Studio新建一個專案,修改App Module的build.gradle檔案,把compileSdkVersion和targetSdkVersion改為23,因為Material Design支援庫需要Android 5.0以上作為編譯SDK。
同時要加入相關依賴包design和RecyclerView支援包。

apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.example.zengyu.recycleview"
minSdkVersion 21 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:recyclerview-v7:23.0.1' compile 'com.android.support:design:23.0.1' }

2.生命週期

一個RecyclerView的Item載入是有順序的,類似於Activity的生命週期(姑且這麼叫),具體可以對adapter的每個方法進行重寫打下日誌進行檢視,具體大致為:

getItemViewType(獲取顯示型別,返回值可在onCreateViewHolder中拿到,以決定載入哪種ViewHolder)

onCreateViewHolder(載入ViewHolder的佈局)

onViewAttachedToWindow(當Item進入這個頁面的時候呼叫)

onBindViewHolder(將資料繫結到佈局上,以及一些邏輯的控制就寫這啦)

onViewDetachedFromWindow(當Item離開這個頁面的時候呼叫)

onViewRecycled(當Item被回收的時候呼叫)

3 基本使用

RecyclerView架構,提供了一種插拔式的體驗,高度的解耦,異常的靈活,通過設定它提供的不同LayoutManager,ItemDecoration , ItemAnimator實現令人瞠目的效果。

  • 你想要控制其顯示的方式,請通過佈局管理器LayoutManager
  • 你想要控制Item間的間隔(可繪製),請通過ItemDecoration
  • 你想要控制Item增刪的動畫,請通過ItemAnimator
  • 你想要控制點選、長按事件,請自己寫(在adapter裡面繫結控制元件加)

3.程式碼實現

看下主佈局就是這麼簡單: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"
tools:context=".MainActivity">
    <android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none" />
</RelativeLayout>
然後要想實現列表效果也是很簡單,分幾步走就好了
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
//如果可以確定每個item的高度是固定的,設定這個選項可以提高效能
 mRecyclerView.setHasFixedSize(true);

// use a linear layout manager
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);

// specify an adapter (see also next example)
myDataset = new String[]{"JAVA", "Objective-C", "C", "C++", "Swift",
"GO", "JavaScript", "Python", "Ruby", "HTML", "SQL"};
mAdapter = new MyAdapter(myDataset);
mRecyclerView.setAdapter(mAdapter);
         1.跟ListView 一樣 需要一個 Adapter

  2.跟ListView 一樣 需要一個 ViewHolder

  3.有點不同了, 需要一個LayoutManager

  然後可以自定義分割線和動畫效果,而且不再有條目事件必須自己去寫onclick裡面的方法。

目前SDK中提供了三種自帶的LayoutManager:

  • LinearLayoutManager

  • GridLayoutManager

  • StaggeredGridLayoutManager

然後實現就在於item增加、刪除的動畫也是可配置的。接下來看一下ItemAnimator,最簡單的就是
SlideInOutLeftItemAnimator : which applies a slide in/out from/to the left animation
        SlideInOutRightItemAnimator : which applies a slide in/out from/to the right animation
        SlideInOutTopItemAnimator : which applies a slide in/out from/to the top animation
        SlideInOutBottomItemAnimator : which applies a slide in/out from/to the bottom animation
        ScaleInOutItemAnimator : which applies a scale animation
        SlideScaleInOutRightItemAnimator : which applies a scale animation with a slide in/out from/to the right animation


如果你是需要更多的效果,github有很多程式碼是可以借鑑的。然後我們就來寫一下分割線啦:
package com.example.zengyu.recycleview.widget;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.ColorRes;
import android.support.annotation.DimenRes;
import android.support.annotation.DrawableRes;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public abstract class FlexibleDividerDecoration extends RecyclerView.ItemDecoration {
private static final int DEFAULT_SIZE = 2;
    private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
    };
    protected enum DividerType {
DRAWABLE, PAINT, COLOR
    }
protected DividerType mDividerType = DividerType.DRAWABLE;
    protected VisibilityProvider mVisibilityProvider;
    protected PaintProvider mPaintProvider;
    protected ColorProvider mColorProvider;
    protected DrawableProvider mDrawableProvider;
    protected SizeProvider mSizeProvider;
    protected boolean mShowLastDivider;
    private Paint mPaint;
    protected FlexibleDividerDecoration(Builder builder) {
if (builder.mPaintProvider != null) {
mDividerType = DividerType.PAINT;
mPaintProvider = builder.mPaintProvider;
} else if (builder.mColorProvider != null) {
mDividerType = DividerType.COLOR;
mColorProvider = builder.mColorProvider;
mPaint = new Paint();
setSizeProvider(builder);
} else {
mDividerType = DividerType.DRAWABLE;
            if (builder.mDrawableProvider == null) {
TypedArray a = builder.mContext.obtainStyledAttributes(ATTRS);
                final Drawable divider = a.getDrawable(0);
a.recycle();
mDrawableProvider = new DrawableProvider() {
@Override
public Drawable drawableProvider(int position, RecyclerView parent) {
return divider;
}
                };
} else {
mDrawableProvider = builder.mDrawableProvider;
}
mSizeProvider = builder.mSizeProvider;
}
mVisibilityProvider = builder.mVisibilityProvider;
mShowLastDivider = builder.mShowLastDivider;
}
private void setSizeProvider(Builder builder) {
mSizeProvider = builder.mSizeProvider;
        if (mSizeProvider == null) {
mSizeProvider = new SizeProvider() {
@Override
public int dividerSize(int position, RecyclerView parent) {
return DEFAULT_SIZE;
}
            };
}
    }
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
int lastChildPosition = -1;
        int childCount = mShowLastDivider ? parent.getChildCount() : parent.getChildCount() - 1;
        for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
            int childPosition = parent.getChildAdapterPosition(child);
            if (childPosition < lastChildPosition) {
// Avoid remaining divider when animation starts
continue;
}
lastChildPosition = childPosition;
            if (ViewCompat.getAlpha(child) < 1) {
// Avoid remaining divider when animation starts
continue;
}
if (mVisibilityProvider.shouldHideDivider(childPosition, parent)) {
continue;
}
Rect bounds = getDividerBound(childPosition, parent, child);
            switch (mDividerType) {
case DRAWABLE:
Drawable drawable = mDrawableProvider.drawableProvider(childPosition, parent);
drawable.setBounds(bounds);
drawable.draw(c);
                    break;
                case PAINT:
mPaint = mPaintProvider.dividerPaint(childPosition, parent);
c.drawLine(bounds.left, bounds.top, bounds.right, bounds.bottom, mPaint);
                    break;
                case COLOR:
mPaint.setColor(mColorProvider.dividerColor(childPosition, parent));
mPaint.setStrokeWidth(mSizeProvider.dividerSize(childPosition, parent));
c.drawLine(bounds.left, bounds.top, bounds.right, bounds.bottom, mPaint);
                    break;
}
        }
    }
@Override
public void getItemOffsets(Rect rect, View v, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(v);
setItemOffsets(rect, position, parent);
}
protected abstract Rect getDividerBound(int position, RecyclerView parent, View child);
    protected abstract void setItemOffsets(Rect outRect, int position, RecyclerView parent);
/**
     * Interface for controlling divider visibility
     */
public interface VisibilityProvider {
/**
         * Returns true if divider should be hidden.
         *
         * @param position Divider position
         * @param parent   RecyclerView
         * @return True if the divider at position should be hidden
         */
boolean shouldHideDivider(int position, RecyclerView parent);
}
/**
     * Interface for controlling paint instance for divider drawing
     */
public interface PaintProvider {
/**
         * Returns {@link Paint} for divider
         *
         * @param position Divider position
         * @param parent   RecyclerView
         * @return Paint instance
         */
Paint dividerPaint(int position, RecyclerView parent);
}
/**
     * Interface for controlling divider color
     */
public interface ColorProvider {
/**
         * Returns {@link android.graphics.Color} value of divider
         *
         * @param position Divider position
         * @param parent   RecyclerView
         * @return Color value
         */
int dividerColor(int position, RecyclerView parent);
}
/**
     * Interface for controlling drawable object for divider drawing
     */
public interface DrawableProvider {
/**
         * Returns drawable instance for divider
         *
         * @param position Divider position
         * @param parent   RecyclerView
         * @return Drawable instance
         */
Drawable drawableProvider(int position, RecyclerView parent);
}
/**
     * Interface for controlling divider size
     */
public interface SizeProvider {
/**
         * Returns size value of divider.
         * Height for horizontal divider, width for vertical divider
         *
         * @param position Divider position
         * @param parent   RecyclerView
         * @return Size of divider
         */
int dividerSize(int position, RecyclerView parent);
}
public static class Builder<T extends Builder> {
private Context mContext;
        protected Resources mResources;
        private PaintProvider mPaintProvider;
        private ColorProvider mColorProvider;
        private DrawableProvider mDrawableProvider;
        private SizeProvider mSizeProvider;
        private VisibilityProvider mVisibilityProvider = new VisibilityProvider() {
@Override
public boolean shouldHideDivider(int position, RecyclerView parent) {
return false;
}
        };
        private boolean mShowLastDivider = false;
        public Builder(Context context) {
mContext = context;
mResources = context.getResources();
}
public T paint(final Paint paint) {
return paintProvider(new PaintProvider() {
@Override
public Paint dividerPaint(int position, RecyclerView parent) {
return paint;
}
            });
}
public T paintProvider(PaintProvider provider) {
mPaintProvider = provider;
            return (T) this;
}
public T color(final int color) {
return colorProvider(new ColorProvider() {
@Override
public int dividerColor(int position, RecyclerView parent) {
return color;
}
            });
}
public T colorResId(@ColorRes int colorId) {
return color(mResources.getColor(colorId));
}
public T colorProvider(ColorProvider provider) {
mColorProvider = provider;
            return (T) this;
}
public T drawable(@DrawableRes int id) {
return drawable(mResources.getDrawable(id));
}
public T drawable(final Drawable drawable) {
return drawableProvider(new DrawableProvider() {
@Override
public Drawable drawableProvider(int position, RecyclerView parent) {
return drawable;
}
            });
}
public T drawableProvider(DrawableProvider provider) {
mDrawableProvider = provider;
            return (T) this;
}
public T size(final int size) {
return sizeProvider(new SizeProvider() {
@Override
public int dividerSize(int position, RecyclerView parent) {
return size;
}
            });
}
public T sizeResId(@DimenRes int sizeId) {
return size(mResources.getDimensionPixelSize(sizeId));
}
public T sizeProvider(SizeProvider provider) {
mSizeProvider = provider;
            return (T) this;
}
public T visibilityProvider(VisibilityProvider provider) {
mVisibilityProvider = provider;
            return (T) this;
}
public T showLastDivider() {
mShowLastDivider = true;
            return (T) this;
}
protected void checkBuilderParams() {
if (mPaintProvider != null) {
if (mColorProvider != null) {
throw new IllegalArgumentException(
"Use setColor method of Paint class to specify line color. Do not provider ColorProvider if you set PaintProvider.");
}
if (mSizeProvider != null) {
throw new IllegalArgumentException(
"Use setStrokeWidth method of Paint class to specify line size. Do not provider SizeProvider if you set PaintProvider.");
}
            }
        }
    }
}
package com.example.zengyu.recycleview.widget;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.DimenRes;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class HorizontalDividerItemDecoration extends FlexibleDividerDecoration {
private MarginProvider mMarginProvider;
    protected HorizontalDividerItemDecoration(Builder builder) {
super(builder);
mMarginProvider = builder.mMarginProvider;
}
@Override
protected Rect getDividerBound(int position, RecyclerView parent, View child) {
Rect bounds = new Rect(0, 0, 0, 0);
        int transitionX = (int) ViewCompat.getTranslationX(child);
        int transitionY = (int) ViewCompat.getTranslationY(child);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
bounds.left = parent.getPaddingLeft() +
mMarginProvider.dividerLeftMargin(position, parent) + transitionX;
bounds.right = parent.getWidth() - parent.getPaddingRight() -
mMarginProvider.dividerRightMargin(position, parent) + transitionX;
        int dividerSize = getDividerSize(position, parent);
        if (mDividerType == DividerType.DRAWABLE) {
bounds.top = child.getBottom() + params.topMargin + transitionY;
bounds.bottom = bounds.top + dividerSize;
} else {
bounds.top = child.getBottom() + params.topMargin + dividerSize / 2 + transitionY;
bounds.bottom = bounds.top;
}
return bounds;
}
@Override
protected void setItemOffsets(Rect outRect, int position, RecyclerView parent) {
outRect.set(0, 0, 0, getDividerSize(position, parent));
}
private int getDividerSize(int position, RecyclerView parent) {
if (mPaintProvider != null) {
return (int) mPaintProvider.dividerPaint(position, parent).getStrokeWidth();
} else if (mSizeProvider != null) {
return mSizeProvider.dividerSize(position, parent);
} else if (mDrawableProvider != null) {
Drawable drawable = mDrawableProvider.drawableProvider(position, parent);
            return drawable.getIntrinsicHeight();
}
throw new RuntimeException("failed to get size")
            
           

相關推薦

RecyclerView優化

        Google 釋出的Material Design支援庫,支援庫應該直接用V4提升到V7了,引入了RecycleView。RecylcerView從去年5.0開始釋出好一陣子了,這貨目前能相容到API 7,直接繼承自Viewgroup,比ListView更為輕

Java效能優化

讓Java應用程式執行是一回事,但讓他們跑得快就是另外一回事了。在面對物件的環境中,效能問題就像來勢凶猛的野獸。但JVM的複雜性將效能調整的複雜程度增加了一個級別。這裡Refcard涵蓋了JVM internals、class loading(Java8中更新以對映最新的元

【推薦】 RAC 效能優化與經典案例剖析

在近期的第七屆資料技術嘉年華上,雲和恩墨技術專家曾令軍做了“RAC效能優化實戰”為主題的演講,分享了從硬體架構、系統與引數配置、應用設計以及工作負載管理這四個層面,剖析在RAC效能優化的過程中,應當注意的問題以及可以借鑑的經驗和思路。我們再次分享出來,希望對各位有所指導

Windows勒索病毒防範、解決方法

windowsxp 殺毒軟件 金山毒霸 下載地址 官方下載 【防禦措施建議】1、安裝殺毒軟件,保持安全防禦功能開啟,比如金山毒霸已可攔截(下載地址http://www.duba.net),微軟自帶的WindowsDefender也可以。2、打開Windows Update自動更新,及時升級

Linux一鍵安裝web環境(阿裏雲ECS服務器)

傳輸 80端口 掛載 iyu 使用 ftp服務 老版本 雲服務 linux服務 摘自阿裏雲服務器官網,此處 一鍵安裝包下載: 點此下載 安裝須知 1、此安裝包可在阿裏雲所有linux系統上部署安裝,此安裝包包含的軟件及版本為: nginx:1.0.15、1.2.5、1.4.

android屏幕適配的

屏幕分辨率 縮放 img 關系 我們 http 分辨 tro pix 一. 核心概念與單位詳解 1. 什麽是屏幕尺寸、屏幕分辨率、屏幕像素密度? 屏幕分辨率越大,手機越清晰 2. 什麽是dp、dip、dpi、sp、px?之間的關系是什麽? dip:Density

Linux編程之UDP SOCKET

應用場景 什麽是 vid 結構體指針 from 好的 conn 能力 cnblogs 這篇文章將對linux下udp socket編程重要知識點進行總結,無論是開發人員應知應會的,還是說udp socket的一些偏僻知識點,本文都會講到。盡可能做到,讀了一篇文章之後,大家對

大型ECShop安裝搬家升級錯誤問題最

item auth prototype c2c params 同時 return ping 屏蔽 【引子】 最近將ECShop框架網站從租用服務器搬家至阿裏雲,雖然模塊及功能上已經被修改的面目全非了,但基礎部分還在。 在這個過程中遇到了很多的WARNIN

win7下安裝Linux實現雙系統

ont c51 item itl command 桌面 ted current 輸入 最近剛剛把原來32位的系統給重新安裝成64位的win7旗艦版,但又想嘗試下Linux,於是在win7下安裝了Linux實現了雙系統,是ubuntu 12.04版本的,據說現在最新的14.

論文檢測省錢

5.1 bds 而且 用途 jpeg har -m 也有 一個 學校是使用的知網論文查重系統,如果去使用別的論文檢測系統不僅浪費錢而且他們之間的報告根本就沒有可比性,因為論文查重系統的不同它收錄的學術論文資源以及算法都是不同的所以結果有偏差才是正常的。因此很多學生也只能使用

maven教程

教程 bean 然而 mave 外部依賴 創建 包含 冗余 快照 maven教程全攻略 我們在開發項目的過程中,會使用一些開源框架、第三方的工具等等,這些都是以jar包的方式被項目所引用,並且有些jar包還會依賴其他的jar包,我們同樣需要添加到項目中,所有這些相關的ja

淘寶優惠券最!省錢

alt bsp 用戶 ima nload 粘貼 list 成功 推廣 工具/原料 淘寶APP 好券捕手APP 首先我們來說一下淘寶優惠券的由來! 淘寶優惠券分兩種 一、公開優惠券 用戶在淘寶店家店鋪就可以直接看到的優惠券 二、賣家用於淘客推廣的優惠券(這種券是不公開的

聯通老用戶換套餐奉上

移動電話 .html 詳細 模版 ges 操作 移動 聯系 等待  聯通互聯網套餐哪個好?近日,很多網友都在討論這個話題,越來越多老用戶通過聯通客服投訴,得以換用資費更加實惠的聯通互聯網套餐。   那麽到底聯通互聯網套餐要如何申請更換,今天就一起來看看聯通老用戶換互聯網套餐

【微軟大法好】VS Tools for AI(2)

port shell orf 方式 virt cnblogs 我們 玩耍 虛擬 接著上文,我們來討論如何使用Azure資源來訓練我們的tensorflow項目。Azure雲我個人用得很多,主要是因為微軟爸爸批了150刀每月的額度,我可以愉快地玩耍。 那麽針對Azure,有成

Vue.js——vue-resource

lam 類型 網絡 java 隱藏 header 做的 response scrip 概述 上一篇我們介紹了如何將$.ajax和Vue.js結合在一起使用,並實現了一個簡單的跨域CURD示例。Vue.js是數據驅動的,這使得我們並不需要直接操作DOM,如果我們不需要使用jQ

Perl Unicode

erl 結果 編程 國際 要求 locale intern 操作 自動 Perl Unicode全攻略 耐心看完本文,相信你今後在unicode處理上不會再有什麽問題。 本文

Windows 系統 Unicode 文件名操作(新建、重命名、枚舉、復制)

for overflow date col left 文件的 函數 參數 splay 常見的那些文件操作函數都不支持,於是為了達到目的,需要各種方法配合,應該是不如其他語言方便。我只是想看看Perl到底是否適合做這件事,於是折騰了一回。文件的建立: 模塊:Win32

【轉】Android Studio打包---從入門到精通

UC store 類型 安裝文件 public alt url tool 描述 原文地址:http://blog.csdn.net/zivensonice/article/details/51672846 初出茅廬 手動打包 怎麽手動打包 項目寫完了,現在需要把應用上傳

Andriod界面設計的分辨率和尺寸適配 轉載

復雜 分別是 太差 content 基礎 hdp art 發布 一點 Andriod界面設計的分辨率和尺寸適配全攻略 轉載 2016年09月27日 17:45:56 第一、屏幕尺寸: 一般表示是手機的實際物理尺寸,屏幕尺寸指屏幕的對角線的長度,單位是英寸,1英寸

axios 之基本介紹與使用(GET 與 POST)

pkg 需要 name comm xmlhttp 基本介紹 markdown pre spa axios axios 是一個基於 Promise 的 HTTP 客戶端,專門為瀏覽器和 node.js 服務 Vue 2.0 官方推薦使用 axios 來代替原來的 Vu