前言
首先和大家道個歉,實在是不好意思,距離上次博客過了很久才更新,由於新項目啓動,朋友那邊又要我幫他做個輔助,加上元旦放假,的確耽誤了很久,現在基本項目工作進度穩定下來,我也要恢復進度,保持博客的穩定了。也不知道大家最近啥時候回家過年,時間也快到年底了,大家是不是都在等年終獎呢,然後回家發紅包,哈哈。不過我最近還遇到點生活上麻煩的事情,嗨,感覺又要奔波,又要折騰一次了。
源碼下載地址在最後!~
簡介
先來看一下上次我們講了什麼,如果沒有看過前面兩篇博文的,可以先去閱讀以下Android RecyclerView 夢幻般的控件 使用解析(一)、Android RecyclerView 夢幻般的控件 使用解析(二)。之前我們講的東西也比較簡單,就是基本如何使用RecyclerView和怎麼添加分隔線,今天開始纔是RecyclerView的魅力所在,讓我們看看夢幻般的她吧~!
使用方法
先把上次留下來的問題再補充一下哈,我們要怎麼自定義分隔線呢?大家也都知道了,我們自定義一個itemdecoration_bg.xml,然後這個東西就比較隨性了,大家可以發揮各自的藝術細胞,當然我只有藝術細菌,也簡單給大家寫一個看看吧,如下:
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<gradient
android:centerColor="#0000ff"
android:endColor="#00ff00"
android:startColor="#00ffff"
android:type="linear" />
<size android:height="2dp"
android:width="2dp"/>
<padding
android:left="5dp"
android:top="1dp"
android:right="5dp"/>
</shape>
基本上我的藝術細菌也就這麼多了,大家可以根據具體需求去畫,反正這個東西比較自由隨意。OK那麼我們繼續,看來這麼多,再加上前面的兩篇博文,的確這個東西用起來好像也真的不簡單,至少比以前的ListView要麻煩,好了,關鍵點來了,我們來看下一,我如果這個改一下呢?看代碼
recyhclerView = (RecyclerView) findViewById(R.id.recycleView);
//recyhclerView.setLayoutManager(new LinearLayoutManager(this));
recyhclerView.setLayoutManager(new GridLayoutManager(this,4));
recyhclerView.setAdapter(new MyRecyclerAdapter());
是不是很神奇,對的,一下子將ListView效果變成了GridView,你想,比如你是商城類的一個APP,在ListView和GridView之間切換是不是超級容易,有木有啊。好了,接下來我們就來講一下這個LayoutManager吧。
RecyclerView.LayoutManager看源碼
public static abstract class LayoutManager {
ChildHelper mChildHelper;
RecyclerView mRecyclerView;
這是一個抽象類,好在系統提供了3個實現類:
LinearLayoutManager 現行管理器,支持橫向、縱向。
GridLayoutManager 網格佈局管理器
StaggeredGridLayoutManager 瀑布就式佈局管理器
那麼我們再來看一下後面那個瀑布式佈局,改一下代碼:
recyhclerView.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL));
當然這樣的寫法實現效果和GridView是一樣的,但是注意一下,StaggeredGridLayoutManager的第二個參數是Orientation,仔細看一下,我們剛纔用的是VERTICAL,大家看意思就能明白了,接下來我們來試試
StaggeredGridLayoutManager.HORIZONTAL
recyhclerView.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.HORIZONTAL));
是不是很神奇,如果你需要一個橫向的GridView,那麼恭喜你,這個輕而易舉就是可以實現。
當然,大家也發現了,我這個分隔線並不適用後面兩種佈局管理器,這裏借鑑一下大神們的分隔線,如下:
DividerGridItemDecoration
package com.mic.blin.myrecyclerview;
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;
/**
* Created by zhaocheng on 2016/1/14.
*/
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());
}
}
}
其實東西並不複雜,主要在getItemOffsets方法中,去判斷是不是最後一行,如果是最後一行,則不需要繪製底部的分隔線了,如果是最後一列的話,那就不需要繪製右邊的分隔線了,去理解一下就可以了,主要學習人家的思想,如何自己去繪製不重要。效果圖:
我們繼續看瀑布流佈局,其實我們已經實現了,因爲我們的高度是固定寫死的,如果我們把高度設置成隨機呢,我們來試試,我們在我們的適配器onBindViewHolder方法中來隨機設置item的高度。
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
ViewGroup.LayoutParams lp = holder.tv.getLayoutParams();
lp.height = (int) (100 + Math.random() * 300);
holder.tv.setLayoutParams(lp);
holder.tv.setText(data.get(position));
}
有木有很容易啊,一下子就實現了瀑布流,畢竟寫個瀑布流還是挺麻煩的。
總結
總的來說,RecyclerView這個控件還是非常好用的,也是非常人性化的,當然也是對以前的ListView和GridView等控件的一種整合吧,把更多的自由交給開發人員,簡單用法很簡單,當然如果要加入點擊事件,滑動事件,觸摸時間,下拉,上拉事件的話,答題思路和ListView肯定是差不多的,所以大家有興趣也可以去自己嘗試寫一下,東西不難,但是好用。
PS
到這裏,大家不知道還怎麼看待這個控件,我是超級喜歡的,我覺得也不用多久,基於RecyclerView的第三方類似於RefreshListView的框架也會橫空出世吧。基本上RecyclerView也就講到這裏了,畢竟生活在上海,現在各種繁瑣的事情,今晚回家又有煩心事要處理,真的是像狗一樣的生活。