Android RecyclerView區(qū)分視圖類型的Divider的實(shí)現(xiàn)
我們都知道support庫有一個(gè)DividerItemDecoration, 可以作為Item之間的分隔線(divider)。但它作用以后所有的item之間都會(huì)有這個(gè)分隔線,實(shí)際情況往往是:recyclerView中存在多種的視圖類型(viewType), 我們只是需要在某一類型的視圖后添加分隔線。
要實(shí)現(xiàn)這種分隔線效果并不是什么難事,既然是某一類型有這個(gè)分隔線,那在直接在這種視圖的layout文件上增加如下一個(gè)bottomLine界面元素妥妥的:
<View android:layout_width="match_parent" android:layout_height="0.5dp" android:background="@color/colorGrayLight" />
但如果添加這樣一個(gè)界面元素導(dǎo)致新增一層布局那感覺代價(jià)有點(diǎn)大。另外一種情況,如果當(dāng)前這個(gè)視圖由于某種原因存在padding,而期望的分隔線是穿透整個(gè)布局的,那添加bottomLine的做法也是行不通的;還有一種情況同一類型布局在一個(gè)頁面有分隔線,在另一個(gè)頁面沒有分隔線;總之就是希望分隔線和視圖內(nèi)容無關(guān)。所以我們需要一種類似DividerItemDecoration的decoration,它能針對(duì)某些viewType起作用。
先要了解一下RecyclerView.ItemDecoration,它有2個(gè)重要的回調(diào)方法:onDrawOver和getItemOffsets。onDrawOver其實(shí)是一種應(yīng)用多個(gè)item的方法,所以無論如何都需要一個(gè)遍歷操作。需要理解的是getItemOffsets中outRect這個(gè)輸出型參數(shù),雖然是一個(gè)Rect類型,但并不表示任何范圍,而只是一個(gè)item四周的間隔距離:
outRect參數(shù)各域的含義
我們思路已經(jīng)很清楚了: 在getItemOffsets中判斷當(dāng)前view的類型(parent.getChildViewHolder(view)), 如果是我們需要的類型設(shè)置對(duì)應(yīng)的bottom;在onDrawOver中我們遍歷recyclerView的child,同樣如果是我們需要的類型將分隔線畫在對(duì)應(yīng)位置上就行了;這個(gè)decoration可以針對(duì)任意一種或者幾種類型設(shè)置不種的drawable,我們當(dāng)前用SparseArray存儲(chǔ),key就是視圖的viewType
private final SparseArrayCompat<Drawable> mDividers = new SparseArrayCompat<>(2);
同時(shí)我們可以設(shè)置這個(gè)item的高度,當(dāng)Drawable為null時(shí)相當(dāng)于一個(gè)透明的間隙,不為null時(shí)具有強(qiáng)制指定的高度。
同樣我們還要考慮方向:layoutManager為橫向和豎向的情況,無它,只是畫的位置不同而已。
話不多說了,上代碼:
import android.graphics.drawable.Drawable; import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; public class ViewTypeDivider extends ItemHolderDivider { @Override protected int keyFrom(RecyclerView.ViewHolder holder) { return holder.getItemViewType(); } public ViewTypeDivider put(int viewType, Drawable drawable) { putDrawable(viewType, drawable); return this; } public ViewTypeDivider put(int viewType, @Nullable Drawable drawable, int height) { putHeight(viewType, drawable, height); return this; } }
import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.annotation.Nullable; import android.support.v4.util.SparseArrayCompat; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; abstract class ItemHolderDivider extends RecyclerView.ItemDecoration { private final SparseArrayCompat<Drawable> mDividers = new SparseArrayCompat<>(2); private final SparseArrayCompat<Integer> mHeights = new SparseArrayCompat<>(2); protected abstract int keyFrom(RecyclerView.ViewHolder holder); @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { final int childCount = parent.getChildCount(); final int width = parent.getWidth(); final int height = parent.getHeight(); for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) { final View view = parent.getChildAt(childViewIndex); RecyclerView.ViewHolder holder = parent.getChildViewHolder(view); int key = keyFrom(holder); if (isVertical(parent)) { drawBottom(c, key, (int) view.getY() + view.getHeight(), width); drawTop(c, -key, (int) view.getY(), width); } else { drawRight(c, key, (int) view.getX() + view.getWidth(), height); drawLeft(c, -key, (int) view.getX(), height); } } } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { RecyclerView.ViewHolder holder = parent.getChildViewHolder(view); int key = keyFrom(holder); if (isVertical(parent)) { outRect.bottom = getHeight(key); outRect.top = getHeight(-key); } else { outRect.right = getHeight(key); outRect.left = getHeight(-key); } } private void drawBottom(Canvas c, int key, int y, int width) { Drawable d = mDividers.get(key); if (d != null) { d.setBounds(0, y, width, y + getHeight(key, d)); d.draw(c); } } private void drawTop(Canvas c, int key, int y, int width) { Drawable d = mDividers.get(key); if (d != null) { d.setBounds(0, y - getHeight(key, d), width, y); d.draw(c); } } private void drawRight(Canvas c, int key, int x, int height) { Drawable d = mDividers.get(key); if (d != null) { d.setBounds(x, 0, x + getHeight(key, d), height); d.draw(c); } } private void drawLeft(Canvas c, int key, int x, int height) { Drawable d = mDividers.get(key); if (d != null) { d.setBounds(x - getHeight(key, d), 0, x, height); d.draw(c); } } final void putDrawable(int key, Drawable drawable) { mDividers.put(key, drawable); } final void putHeight(int key, @Nullable Drawable drawable, int height) { if (drawable != null) { mDividers.put(key, drawable); } mHeights.put(key, height); } private int getHeight(int key) { Drawable d = mDividers.get(key); return getHeight(key, d); } private int getHeight(int key, @Nullable Drawable d) { int index = mHeights.indexOfKey(key); return index < 0 ? d == null ? 0 : d.getIntrinsicHeight() : mHeights.valueAt(index); } private boolean isVertical(RecyclerView parent) { RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); return !(layoutManager instanceof LinearLayoutManager) || ((LinearLayoutManager) layoutManager).getOrientation() == LinearLayoutManager.VERTICAL; } }
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android中使用RecyclerView實(shí)現(xiàn)下拉刷新和上拉加載
- Android中RecyclerView布局代替GridView實(shí)現(xiàn)類似支付寶的界面
- Android中RecyclerView實(shí)現(xiàn)橫向滑動(dòng)代碼
- Android RecyclerView實(shí)現(xiàn)下拉刷新和上拉加載
- Android中RecyclerView實(shí)現(xiàn)多級(jí)折疊列表效果(二)
- Android RecyclerView網(wǎng)格布局(支持多種分割線)詳解(2)
- Android項(xiàng)目實(shí)戰(zhàn)之仿網(wǎng)易新聞的頁面(RecyclerView )
- Android RecyclerView 上拉加載更多及下拉刷新功能的實(shí)現(xiàn)方法
- Android中RecyclerView嵌套滑動(dòng)沖突解決的代碼片段
- Android使用RecyclerView實(shí)現(xiàn)水平滾動(dòng)控件
相關(guān)文章
Android仿QQ微信實(shí)時(shí)監(jiān)測(cè)網(wǎng)絡(luò)狀態(tài)
這篇文章主要為大家詳細(xì)介紹了Android仿QQ微信實(shí)時(shí)監(jiān)測(cè)網(wǎng)絡(luò)狀態(tài),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05android開發(fā)實(shí)現(xiàn)列表控件滾動(dòng)位置精確保存和恢復(fù)的方法(推薦)
下面小編就為大家?guī)硪黄猘ndroid開發(fā)實(shí)現(xiàn)列表控件滾動(dòng)位置精確保存和恢復(fù)的方法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03Android實(shí)現(xiàn)ViewPager無限循環(huán)效果(二)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)ViewPager無限循環(huán)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05基于Android RecyclerView實(shí)現(xiàn)宮格拖拽效果
在Android發(fā)展的進(jìn)程中,網(wǎng)格布局一直比較有熱度,其中一個(gè)原因是對(duì)用戶來說便捷操作,對(duì)app廠商而言也會(huì)帶來很多的曝光量,本篇我們會(huì)使用RecyclerView來實(shí)現(xiàn)網(wǎng)格拖拽,本篇將結(jié)合圖片分片案例,實(shí)現(xiàn)拖拽效果,需要的朋友可以參考下2024-03-03Android仿百度地圖小度語音助手的貝塞爾曲線動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了Android仿百度地圖小度語音助手的貝塞爾曲線動(dòng)畫,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07超實(shí)用的Android手勢(shì)鎖制作實(shí)例教程
這篇文章主要介紹了一個(gè)超實(shí)用的Android手勢(shì)鎖制作實(shí)例教程,普通的圓環(huán)形圖標(biāo)變換,在App和系統(tǒng)的鎖屏界面中都可以調(diào)用,需要的朋友可以參考下2016-04-04Android ListView數(shù)據(jù)的分批顯示功能
本文通過實(shí)例代碼給大家分享了Android ListView數(shù)據(jù)的分批顯示功能,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友參考下吧2017-04-04Android調(diào)用系統(tǒng)圖庫獲取圖片的方法
這篇文章主要為大家詳細(xì)介紹了Android調(diào)用系統(tǒng)圖庫獲取圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08Android WebView實(shí)現(xiàn)頂部進(jìn)度條
這篇文章主要為大家詳細(xì)介紹了Android WebView實(shí)現(xiàn)頂部進(jìn)度條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11Android Activity與Fragment之間的跳轉(zhuǎn)實(shí)例詳解
這篇文章主要介紹了Android Activity與Fragment之間的跳轉(zhuǎn)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-02-02