Android RecyclerView 夢幻般的控件 使用解析(三)

前言

首先和大家道個歉,實在是不好意思,距離上次博客過了很久才更新,由於新項目啓動,朋友那邊又要我幫他做個輔助,加上元旦放假,的確耽誤了很久,現在基本項目工作進度穩定下來,我也要恢復進度,保持博客的穩定了。也不知道大家最近啥時候回家過年,時間也快到年底了,大家是不是都在等年終獎呢,然後回家發紅包,哈哈。不過我最近還遇到點生活上麻煩的事情,嗨,感覺又要奔波,又要折騰一次了。

源碼下載地址在最後!~


簡介

先來看一下上次我們講了什麼,如果沒有看過前面兩篇博文的,可以先去閱讀以下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也就講到這裏了,畢竟生活在上海,現在各種繁瑣的事情,今晚回家又有煩心事要處理,真的是像狗一樣的生活。

下載地址

http://download.csdn.net/detail/qq_25867141/9404331

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章