天天看點

Android開發之RecyclerView的使用全解

轉自:http://blog.csdn.net/dmk877/article/details/50816933

自Android 5.0之後,谷歌公司推出了RecylerView控件,RecylerView,我想看到一個新名詞後大部分人會首先發出一個疑問,recylerview是什麼?為什麼會有recylerview也就是說recylerview的優點是什麼?recylerview怎麼用?接下來就對這幾個問題來一起讨論一下recylerview,如有謬誤歡迎批評指正,如有疑問請留言。

通過本篇部落格,你将學到以下知識點

①RecyclerView與ListView相比它的優點

②RecyclerView的初步用法

③RecyclerView增加分隔線

④RecyclerView更改分隔線的樣式

⑤RecyclerView的Adapter的用法

⑥RecyclerView.Adapter中重新整理的幾個方法的對比

⑦給RecyclerView增加條目點選事件

1.RecyclerView是什麼?

RecylerView是support-v7包中的新元件,是一個強大的滑動元件,與經典的ListView相比,同樣擁有item回收複用的功能,這一點從它的名字recylerview即回收view也可以看出。看到這也許有人會問,不是已經有ListView了嗎,為什麼還要RecylerView呢?這就牽扯到第二個問題了。
           

2.RecyclerView的優點是什麼?

根據官方的介紹RecylerView是ListView的更新版,既然如此那RecylerView必然有它的優點,現就RecylerView相對于ListView的優點羅列如下:
           

①RecylerView封裝了viewholder的回收複用,也就是說RecylerView标準化了ViewHolder,編寫Adapter面向的是ViewHolder而不再是View了,複用的 邏輯被封裝了,寫起來更加簡單。

②提供了一種插拔式的體驗,高度的解耦,異常的靈活,針對一個Item的顯示RecylerView專門抽取出了相應的類,來控制Item的顯示,使其的擴充性非常強。例如:你想控制橫向或者縱向滑動清單效果可以通過LinearLayoutManager這個類來進行控制(與GridView效果對應的是GridLayoutManager,與瀑布流對應的還有StaggeredGridLayoutManager等),也就是說RecylerView不再拘泥于ListView的線性展示方式,它也可以實作GridView的效果等多種效果。你想控制Item的分隔線,可以通過繼承RecylerView的ItemDecoration這個類,然後針對自己的業務需求去抒寫代碼。

③可以控制Item增删的動畫,可以通過ItemAnimator這個類進行控制,當然針對增删的動畫,RecylerView有其自己預設的實作。

3.RecyclerView的用法

3.1 RecyclerView的初步用法(包括RecyclerView.Adapter用法)

說了這麼多,可能大家最關心的就是RecylerView應該怎麼用,我們先來讨論讨論RecylerView的用法的理論知識,然後結合一個執行個體來體驗一下RecylerView的優勢首先我們需要明白的一點是使用RecylerView必須導入support-v7包,在上面我提到過RecylerView高度的解耦,異常的靈活谷歌給我們提供了多個類來控制Item的顯示。
           

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

recyclerView = (RecyclerView) findViewById(R.id.recyclerView);  
LinearLayoutManager layoutManager = new LinearLayoutManager(this );  
//設定布局管理器  
recyclerView.setLayoutManager(layoutManager);  
//設定為垂直布局,這也是預設的  
layoutManager.setOrientation(OrientationHelper. VERTICAL);  
//設定Adapter  
recyclerView.setAdapter( recycleAdapter);  
 //設定分隔線  
recyclerView.addItemDecoration( new DividerGridItemDecoration(this ));  
//設定增加或删除條目的動畫  
recyclerView.setItemAnimator( new DefaultItemAnimator());  
           

可以看到對RecylerView的設定過程,比ListView要複雜一些,這也是RecylerView高度解耦的表現,雖然代碼抒寫上有點複雜,但它的擴充性是極高的。

在了解了RecyclerView的一些控制之後,緊接着來看看它的Adapter的寫法,RecyclerView的Adapter與ListView的Adapter還是有點差別的,RecyclerView.Adapter,需要實作3個方法:

①onCreateViewHolder()

這個方法主要生成為每個Item inflater出一個View,但是該方法傳回的是一個ViewHolder。該方法把View直接封裝在ViewHolder中,然後我們面向的是ViewHolder這個執行個體,當然這個ViewHolder需要我們自己去編寫。直接省去了當初的convertView.setTag(holder)和convertView.getTag()這些繁瑣的步驟。

②onBindViewHolder()

這個方法主要用于适配渲染資料到View中。方法提供給你了一個viewHolder,而不是原來的convertView。

③getItemCount()

這個方法就類似于BaseAdapter的getCount方法了,即總共有多少個條目。

執行個體:接着來幾個小的執行個體幫助大家更深入的了解RecyclerView的用法,首先來實作一個最簡單的清單,效果如下

這種效果的MainAcitivity的代碼如下

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

package com.example.reclerviewpractice;  

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

import com.example.reclerviewpractice.adapter.MyRecyclerAdapter;  

import android.annotation.SuppressLint;  
import android.os.Bundle;  
import android.support.v7.app.ActionBarActivity;  
import android.support.v7.widget.DefaultItemAnimator;  
import android.support.v7.widget.LinearLayoutManager;  
import android.support.v7.widget.OrientationHelper;  
import android.support.v7.widget.RecyclerView;  

public class MainActivity extends ActionBarActivity {  

     private RecyclerView recyclerView;  
     private List<String> mDatas;  
     private MyRecyclerAdapter recycleAdapter;  

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

            recyclerView = (RecyclerView) findViewById(R.id.recyclerView );  

           initData();  
            recycleAdapter= new MyRecyclerAdapter(MainActivity.this , mDatas );  
           LinearLayoutManager layoutManager = new LinearLayoutManager(this);  
            //設定布局管理器  
            recyclerView.setLayoutManager(layoutManager);  
            //設定為垂直布局,這也是預設的  
           layoutManager.setOrientation(OrientationHelper.VERTICAL);  
            //設定Adapter  
            recyclerView.setAdapter( recycleAdapter);  
            //設定增加或删除條目的動畫  
            recyclerView.setItemAnimator(new DefaultItemAnimator());  

     }  

     private void initData() {  
            mDatas = new ArrayList<String>();  
            for ( int i=0; i < 40; i++) {  
                 mDatas.add( "item"+i);  
           }  
     }  
}  
           

RecyclerView的Adapter的代碼如下:

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

package com.example.reclerviewpractice.adapter;  

import java.util.List;  

import com.example.reclerviewpractice.R;  

import android.content.Context;  
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 MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.MyViewHolder> {  

     private List<String> mDatas;  
     private Context mContext;  
     private LayoutInflater inflater;  

     public MyRecyclerAdapter(Context context, List<String> datas){  
            this. mContext=context;  
            this. mDatas=datas;  
            inflater=LayoutInflater. from(mContext);  
     }  

     @Override  
     public int getItemCount() {  

            return mDatas.size();  
     }  

     //填充onCreateViewHolder方法傳回的holder中的控件  
     @Override  
     public void onBindViewHolder(MyViewHolder holder, final int position) {  

           holder.tv.setText( mDatas.get(position));  
     }  

     //重寫onCreateViewHolder方法,傳回一個自定義的ViewHolder  
     @Override  
     public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  

           View view = inflater.inflate(R.layout. item_home,parent, false);  
           MyViewHolder holder= new MyViewHolder(view);  
            return holder;  
     }  

     class MyViewHolder extends ViewHolder{  

           TextView tv;  

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

     }  
}  
           

可以看到RecyclerView标準化了ViewHolder,編寫 Adapter面向的是ViewHoder而不在是View了,複用的邏輯被封裝了,寫起來更加簡單。其實它的寫法與BaseAdapter的寫法是差不多的,大家可以對比下它與getView方法寫法的差別,在onCreateViewHolder方法中初始化了一個View,然後傳回一個ViewHolder,這個傳回的ViewHolder類似于之前在getView中的convertView.getTag(),然後在onBindViewHolder方法中去給這個ViewHolder中的控件填充值。其實它的原理跟getView是差不多的,隻是做了封裝,我們寫起來比較簡潔。到這裡,看到上述運作效果可能有很多人會說,這效果太醜了,連個分隔線都沒有,不要急,我們一步一步來。

3.2 RecyclerView增加分隔線

前面我們說到可以通過RecyclerView.addItemDecoration(ItemDecoration decoration)這個方法進行設定,其中它需要的參數就是我們自己定義的繼承自ItemDecoration的一個對象。我們可以建立一個繼承RecyclerView.ItemDecoration類來繪制分隔線,通過ItemDecoration可以讓我們每一個Item從視覺上面互相分開來,例如ListView的divider非常相似的效果。當然像我們上面的例子ItemDecoration我們沒有設定也沒有報錯,那說明ItemDecoration我們并不是強制需要使用,作為我們開發者可以設定或者不設定Decoration的。實作一個ItemDecoration,系統提供的ItemDecoration是一個抽象類,内部除去已經廢棄的方法以外,我們主要實作以下三個方法:
           

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

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(RectoutRect, View view,RecyclerView parent,State state) {   
          getItemOffsets(outRect,((LayoutParams)view.getLayoutParams()).getViewLayoutPosition(),parent);   
      }   
  }  
           

又因為當我們RecyclerView在進行繪制的時候會進行繪制Decoration,那麼會去調用onDraw和onDrawOver方法,那麼這邊我們其實隻要去重寫onDraw和getItemOffsets這兩個方法就可以實作啦。然後LayoutManager會進行Item布局的時候,會去調用getItemOffset方法來計算每個Item的Decoration合适的尺寸,下面我們來具體實作一個Decoration,DividerItemDecoration.Java

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

package com.example.reclerviewpractice;  

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;  

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) {  
        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, int itemPosition, RecyclerView parent) {  
        if (mOrientation == VERTICAL_LIST) {  
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());  
        }else{  
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);  
        }  
    }  
}  
           

在這裡我們采用系統主題(android.R.attr.listDivider)來設定成分隔線的,然後來擷取尺寸,位置進行setBound(),繪制,接着通過outRect.set()來設定繪制整個區域範圍,當然了它是有兩種情況的一種LinearLayoutManager.HORIZONTAL另外一種LinearLayoutManager.VERTICAL需要分别對其進行處理,最後不要忘記往RecyclerView中設定該自定義的分割線,然後在MainActivity中加上一句recyclerView .addItemDecoration(new DividerItemDecoration(MainActivity.this,LinearLayoutManager.VERTICAL))即給RecyclerView增加分隔線。然後運作,效果如下:

可以看到已經有了分隔線,跟ListView的效果基本一緻了。當然了,既然谷歌給我們提供了這個專門添加分隔線的方法,那它肯定會允許我們自定義分隔線的樣式,不然把這個方法抽取出來也沒有任何意義。

3.3 改變分隔線樣式

那麼怎麼更改分隔線的樣式呢?在上面的DividerItemDecoration這個類中可以看到這個分隔線是跟ListView一樣的,即系統的預設的樣式,是以我們可以在styles的xml檔案中進行更改,更改如下:
           

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

<!-- Application theme. -->  
    <style name ="AppTheme" parent="AppBaseTheme">  
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->  
        <item name= "android:listDivider">@drawable/divider </item >   
    </style >  
           

divider的内容如下:

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

<?xml version="1.0" encoding= "utf-8"?>  
<shape xmlns:android="http://schemas.android.com/apk/res/android"  
    android:shape="rectangle" >  

        <!-- 填充的顔色 -->  
       <solid android:color ="@color/color_red"/>  

      <!--  線條大小 -->  
      <size android:height ="1dp" android:width ="1dp"/>  
</shape>  
           

修改之後運作效果如下:

可以看到分隔線的顔色變了,當然了這隻是一個小例子,我們可以按照業務需求去更改,這樣就基本實作了ListView的效果,看到這肯定會有人說,這尼瑪,好麻煩,還不如ListView簡單呢,從上面的代碼量看來确實是使用起來很複雜,但是如果此時你想将這個清單以GridView的形式展示出來,用RecylerView僅僅是換一行代碼的事情,

在上面的代碼中我們使用了

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

LinearLayoutManager layoutManager = new LinearLayoutManager(this);  
 //設定布局管理器  
recyclerView.setLayoutManager(layoutManager);  
           

RecyclerView.LayoutManager是一個抽象類,系統為我們提供了三個實作類

①LinearLayoutManager即線性布局,這個是在上面的例子中我們用到的布局

②GridLayoutManager即表格布局

③StaggeredGridLayoutManager即流式布局,如瀑布流效果

假如将上述例子換成GridView的效果,那麼相應的代碼應該這樣改

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

recyclerView .setLayoutManager(new GridLayoutManager( this,4));  
           

除此之外上述的分隔線也要做相應的更改,因為在上述DividerItemDecoration這個方法中從

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

final int left = parent.getPaddingLeft();  
final int right = parent.getWidth() - parent.getPaddingRight();  
           

這兩行我們可以看出來,它是繪制了一條線這條線就是從RecyclerView去掉左右邊距後,剩餘的部分,因為當顯示成ListView時每一行就一個Item是以整體效果看上去就跟ListView差不多,而當展示成GridView那樣的效果時,每一行就不止一個條目了,而有可能是多個,是以這個類就不再适用了,我們需要重新寫一個,這裡我就直接用鴻洋大神寫的了,它的部落格位址:http://blog.csdn.net/lmj623565791/article/details/45059587

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

package com.example.reclerviewpractice;  

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.GridLayoutManager;  
import android.support.v7.widget.RecyclerView;  
import android.support.v7.widget.RecyclerView.LayoutManager;  
import android.support.v7.widget.RecyclerView.State;  
import android.support.v7.widget.StaggeredGridLayoutManager;  
import android.view.View;  

/** 
 * 
 * @author zhy 
 * 
 */  
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration  
{  

     private static final int[] ATTRS = new int[] { android.R.attr.listDivider };  
     private Drawable mDivider;  

     public DividerGridItemDecoration(Context context)  
     {  
            final TypedArray a = context.obtainStyledAttributes(ATTRS );  
            mDivider = a.getDrawable(0);  
           a.recycle();  
     }  

     @Override  
     public void onDraw(Canvas c, RecyclerView parent, State state)  
     {  

           drawHorizontal(c, parent);  
           drawVertical(c, parent);  

     }  

     private int getSpanCount(RecyclerView parent)  
     {  
            // 列數  
            int spanCount = -1;  
           LayoutManager layoutManager = parent.getLayoutManager();  
            if (layoutManager instanceof GridLayoutManager)  
           {  

                spanCount = ((GridLayoutManager) layoutManager).getSpanCount();  
           } else if (layoutManager instanceof StaggeredGridLayoutManager)  
           {  
                spanCount = ((StaggeredGridLayoutManager) layoutManager)  
                           .getSpanCount();  
           }  
            return spanCount;  
     }  

     public void drawHorizontal(Canvas c, RecyclerView parent)  
     {  
            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.getLeft() - params.leftMargin;  
                 final int right = child.getRight() + params.rightMargin  
                           + mDivider.getIntrinsicWidth();  
                 final int top = child.getBottom() + params.bottomMargin;  
                 final int bottom = top + mDivider.getIntrinsicHeight();  
                 mDivider.setBounds(left, top, right, bottom);  
                 mDivider.draw(c);  
           }  
     }  

     public void drawVertical(Canvas c, RecyclerView parent)  
     {  
            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.getTop() - params.topMargin;  
                 final int bottom = child.getBottom() + params.bottomMargin;  
                 final int left = child.getRight() + params.rightMargin;  
                 final int right = left + mDivider.getIntrinsicWidth();  

                 mDivider.setBounds(left, top, right, bottom);  
                 mDivider.draw(c);  
           }  
     }  

     private boolean isLastColum(RecyclerView parent, int pos, int spanCount,  
                 int childCount)  
     {  
           LayoutManager layoutManager = parent.getLayoutManager();  
            if (layoutManager instanceof GridLayoutManager)  
           {  
                 if ((pos + 1) % spanCount == 0) // 如果是最後一列,則不需要繪制右邊  
                {  
                      return true;  
                }  
           } else if (layoutManager instanceof StaggeredGridLayoutManager)  
           {  
                 int orientation = ((StaggeredGridLayoutManager) layoutManager)  
                           .getOrientation();  
                 if (orientation == StaggeredGridLayoutManager.VERTICAL )  
                {  
                      if ((pos + 1) % spanCount == 0) // 如果是最後一列,則不需要繪制右邊  
                     {  
                            return true;  
                     }  
                } else  
                {  
                     childCount = childCount - childCount % spanCount;  
                      if (pos >= childCount) // 如果是最後一列,則不需要繪制右邊  
                            return true;  
                }  
           }  
            return false;  
     }  

     private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,  
                 int childCount)  
     {  
           LayoutManager layoutManager = parent.getLayoutManager();  
            if (layoutManager instanceof GridLayoutManager)  
           {  
                childCount = childCount - childCount % spanCount;  
                 if (pos >= childCount) // 如果是最後一行,則不需要繪制底部  
                      return true;  
           } else if (layoutManager instanceof StaggeredGridLayoutManager)  
           {  
                 int orientation = ((StaggeredGridLayoutManager) layoutManager)  
                           .getOrientation();  
                 // StaggeredGridLayoutManager 且縱向滾動  
                 if (orientation == StaggeredGridLayoutManager.VERTICAL )  
                {  
                     childCount = childCount - childCount % spanCount;  
                      // 如果是最後一行,則不需要繪制底部  
                      if (pos >= childCount)  
                            return true;  
                } else  
                 // StaggeredGridLayoutManager 且橫向滾動  
                {  
                      // 如果是最後一行,則不需要繪制底部  
                      if ((pos + 1) % spanCount == 0)  
                     {  
                            return true;  
                     }  
                }  
           }  
            return false;  
     }  

     @Override  
     public void getItemOffsets(Rect outRect, int itemPosition,  
                RecyclerView parent)  
     {  
            int spanCount = getSpanCount(parent);  
            int childCount = parent.getAdapter().getItemCount();  
            if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最後一行,則不需要繪制底部  
           {  
                outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);  
           } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最後一列,則不需要繪制右邊  
           {  
                outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());  
           } else  
           {  
                outRect.set(0, 0, mDivider.getIntrinsicWidth(),  
                            mDivider.getIntrinsicHeight());  
           }  
     }  
}  
           

别忘了更改分隔線recyclerView .addItemDecoration(new DividerGridItemDecoration(this ));之後運作發現效果如下

可以看到如果你準備好了分隔線的這個類,從ListView效果到GridView效果,隻需要幾行代碼,是不是瞬間感覺高大上了?還有更讓人瞠目結舌的效果,将上述代碼做如下更改

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.HORIZONTAL);  
//設定布局管理器  
recyclerView.setLayoutManager(layoutManager);  
           

這裡需要注意的是StaggeredGridLayoutManager構造的第二個參數傳一個orientation,如果傳入的是StaggeredGridLayoutManager.VERTICAL那麼前面那個參數就代表有多少列;如果傳是StaggeredGridLayoutManager.HORIZONTAL那麼前面那個參數就代表有多少行

運作效果如下

這效果是不是有點逆天?可以看到,固定為4行,變成了左右滑動。有一點需要注意,如果是橫向的時候,item的寬度需要注意去設定,畢竟橫向的寬度沒有限制了,因為控件可以橫向滾動了,另外它還可以實作瀑布流的效果,關于瀑布流我準備後面專門寫一篇部落格。
           

3.4 RecyclerView增加和删除的動畫(包括RecyclerView.Adapter中重新整理的幾個方法的對比)

在上面也提到了控制RecyclerView增加和删除的動畫是通過ItemAnimator這個類來實作的,ItemAnimator這類也是個抽象的類,系統預設給我們提供了一種增加和删除的動畫,下面我們就來看看這種動畫的效果,我們需要做的修改如下:

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

LinearLayoutManager layoutManager = new LinearLayoutManager(this);  
 //設定布局管理器  
recyclerView.setLayoutManager(layoutManager);  
//設定增加或删除條目的動畫  
recyclerView.setItemAnimator( new DefaultItemAnimator());  
           

然後重寫ActionBar的

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

@Override  
     public boolean onCreateOptionsMenu(Menu menu)  
     {  
           getMenuInflater().inflate(R.menu. main, menu);  
            return super.onCreateOptionsMenu(menu);  
     }  

     @Override  
     public boolean onOptionsItemSelected(MenuItem item)  
     {  
            switch (item.getItemId())  
           {  
            case R.id. id_action_add:  
                 recycleAdapter.addData(1);  
                 break;  
            case R.id. id_action_delete:  
                 recycleAdapter.removeData(1);  
                 break;  
           }  
            return true;  
     }  
           

關于R.menu. main中的main.xml這個檔案代碼就不貼了,在最後的一個彙總的例子裡會有

recyclerViewAdapter中增加的兩個方法:

public void addData( int position) {

mDatas.add(position, “Insert One”);

notifyItemInserted(position);

notifyItemRangeChanged(position, mDatas.size());

}

public void removeData( int position) {
      mDatas.remove(position);
      notifyItemRemoved(position);
      notifyItemRangeChanged(position, mDatas.size());
 }
           

這裡需要說一下RecyclerView.Adapter中重新整理資料的幾個方法,一共有這麼幾個方法

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

public final void notifyDataSetChanged()  
public final void notifyItemChanged(int position)  
public final void notifyItemRangeChanged(int positionStart, int itemCount)  
public final void notifyItemInserted(int position)   
public final void notifyItemMoved(int fromPosition, int toPosition)  
public final void notifyItemRangeInserted(int positionStart, int itemCount)  
public final void notifyItemRemoved(int position)  
public final void notifyItemRangeRemoved(int positionStart, int itemCount)  
           

notifyDataSetChanged()這個方法跟我們平時用到的ListView的Adapter的方法一樣,這裡就不多做描述了。

notifyItemChanged(int position),當position位置的資料發生了改變時就會調用這個方法,就會回調對應position的onBindViewHolder()方法了,當然,因為ViewHolder是複用的,是以如果position在目前螢幕以外,也就不會回調了,因為沒有意義,下次position滾動會目前螢幕以内的時候同樣會調用onBindViewHolder()方法重新整理資料了。其他的方法也是同樣的道理。public final void notifyItemRangeChanged(int positionStart, int itemCount),顧名思義,可以重新整理從positionStart開始itemCount數量的item了(這裡的重新整理指回調onBindViewHolder()方法)。

public final void notifyItemInserted(int position),這個方法是在第position位置被插入了一條資料的時候可以使用這個方法重新整理,注意這個方法調用後會有插入的動畫,這個動畫可以使用預設的,也可以自己定義。

public final void notifyItemMoved(int fromPosition, int toPosition),這個方法是從fromPosition移動到toPosition為止的時候可以使用這個方法重新整理

public final void notifyItemRangeInserted(int positionStart, int itemCount),顯然是批量添加。

public final void notifyItemRemoved(int position),第position個被删除的時候重新整理,同樣會有動畫。

将上述更改運作,點選添加和删除按鈕效果圖如下:

public final void notifyItemRangeRemoved(int positionStart, int itemCount),批量删除。

可以看到系統給提供的動畫效果還不錯,當然我們也可以按照業務需求去自己定義動畫效果。

3.5 給RecyclerView的Item添加點選事件

到這裡還有一點從文章開頭到現在我們都沒有提及,就是Item的點選事件RecyclerView監聽事件處理在ListView使用的時候,該控件給我們提供一個onItemClickListener監聽器,這樣當我們點選Item的時候,會回調相關的方法,以便我們友善處理Item點選事件。對于RecyclerView來講,非常可惜的是,該控件沒有給我們提供這樣的内置監聽器方法,不過我們可以進行改造實作,可以這樣實作Item的點選事件的監聽,在我們的adapter中增加這兩個方法
           

public interface OnItemClickListener{

void onClick( int position);

void onLongClick( int position);

}

public void setOnItemClickListener(OnItemClickListener onItemClickListener ){

this. mOnItemClickListener=onItemClickListener;

}

然後onBindViewHolder方法要做如下更改

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

@Override  
     public void onBindViewHolder(MyViewHolder holder, final int position) {  

           holder. tv.setText( mDatas.get(position));  

            if( mOnItemClickListener!= null){  
                holder. itemView.setOnClickListener( new OnClickListener() {  

                      @Override  
                      public void onClick(View v) {  
                           mOnItemClickListener.onClick(position);  
                     }  
                });  

                holder. itemView.setOnLongClickListener( new OnLongClickListener() {  
                      @Override  
                      public boolean onLongClick(View v) {  
                           mOnItemClickListener.onLongClick(position);  
                            return false;  
                     }  
                });  
           }  
     }<span style="color:#333333;">  
</span>  
           

在MainAcitivity中增加

[java] view plain copy

在CODE上檢視代碼片派生到我的代碼片

recycleAdapter.setOnItemClickListener(new OnItemClickListener() {  

              @Override  
              public void onLongClick(int position) {  
                   Toast.makeText(MainActivity.this,"onLongClick事件       您點選了第:"+position+"個Item",0).show();  
              }  

              @Override  
              public void onClick(int position) {  
                   Toast.makeText(MainActivity.this,"onClick事件       您點選了第:"+position+"個Item",0).show();  
              }  
         });  
           

然後運作,效果如下:

可以看到Item的onClick和onLongClick事件都觸發了。到此關于RecyclerView的基本用法就介紹的差不多了,當然,還有幾個點沒有提到,比方說瀑布流、下拉重新整理、上拉加載等,由于篇幅原因這些在後面的更新中都會給大家呈現。最後将本篇部落格所提到的知識點做一個整合,寫到Demo中,大家可以參考,Demo進行學習。好了,這一篇就到這裡了,如果發現什麼錯誤,或者有什麼疑問請留言,感謝您的觀看,謝謝各位的支援。。。

轉載請注明出處:http://blog.csdn.net/dmk877/article/details/50816933

源碼戳這裡

參考部落格:

http://www.cnblogs.com/tiantianbyconan/p/4232560.html

http://blog.csdn.net/lmj623565791/article/details/45059587