1. 程式人生 > >ItemDecoration實現固定懸浮式Item的思路

ItemDecoration實現固定懸浮式Item的思路

寫在前面

這個國慶好像啥事都沒有做就已經過去,為了避免整個國慶的渾渾噩噩。那就在國慶的尾巴之時學一下習,記一個知識點。關於ItemDecoration的作用。在很久之前,我一直把ItemDecoration定義在僅僅是畫Item的分隔線。
然而當我看了很多大神的程式碼和思路,才發現ItemDecoration能做的這麼多。今天主要就是記錄我們經常見到的一個效果,這個效果叫什麼名字,還真不清楚,不過看了下面的效果圖,覺得就知道了:

這裡寫圖片描述

開始

在開始搞這個效果之前,我們先熟悉一下ItemDecoration的簡單用法。


public class TestItemDecoration
extends RecyclerView.ItemDecoration {
/** * 可以實現類似繪製背景的效果,內容在正常的Item下面,被覆蓋。正常我們要結合 * getItemOffsets將正常Item錯開,免得被正常Item覆蓋掉 */ @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDraw(c, parent, state); } //可以繪製在內容的上面,覆蓋在正常的Item內容
@Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDrawOver(c, parent, state); } //實現Item的類似padding的效果,也就是讓我們正常的Item進行移動 @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super
.getItemOffsets(outRect, view, parent, state); } }

我們所看到的XX省,其實就是我們的ItemDecoration,也就是分割線做出來的。其實我們,知道這三個方法的用法,通過這三個方法的組合,我們就可以做出這個效果了。

第一步getItemOffsets():

首先,我們在getItemOffsets這個方法之中先進行Item的移動操作,在特定的position之間移開我們用於顯示XX省的間隔位置,用作分隔符,並未後續的繪製操作做好準備。
(我們可以通過parent.getChildAdapterPosition(view)這個方法獲取到當前Item的position,擁有了position,我們可以通過外部回撥的方式獲取對應的Adapter中的對應Data,然後就可以根據我們的業務判斷是否需要操作getItemOffsets這個方法。)


@Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        int pos = parent.getChildAdapterPosition(view);
        //省略一些判空操作,詳細內容請移步GitHub:https://github.com/zhiaixinyang/PersonalCollect
        if (pos == 0 || isFirstInGroup(pos)) {
            /**
             * isFirstInGroup(pos)自己的方法,通過外部回撥,判斷是不是我們想要顯示的XX省,
             * 如果是,移動我們想要顯示的高度。
             * outRect.top:可以理解為:內邊距的高度
             */
            outRect.top = mGroupHeight;
        }
    }

接下來我們就要開始繪製顯示XX省的這個Item(本質就是分割線ItemDecoration)。這裡我們需要考慮的有點多,我們我們可以看到,在下一個的省替換上一個省顯示的時候,我們有一個擠壓的效果。

第二部onDrawOver():

因為我們的頂部ItemDecoration有懸浮的效果,所以這裡我們使用onDrawOver這個方法進行繪製。


    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);
        final int itemCount = state.getItemCount();
        final int childCount = parent.getChildCount();
        final int left = parent.getLeft() + parent.getPaddingLeft();
        final int right = parent.getRight() - parent.getPaddingRight();
        //標記上一個item對應的Group
        String preGroupName;
        //當前item對應的Group
        String currentGroupName = null;
        //遍歷所有的子View(所有的Item)
        for (int i = 0; i < childCount; i++) {
            View view = parent.getChildAt(i);
            int position = parent.getChildAdapterPosition(view);
            preGroupName = currentGroupName;
            //如果拿不到我們想要繪製的XX省的名字,跳過遍歷過程。也就是正常的Item不做處理(這不是廢話麼- -!)
            currentGroupName = getGroupName(position);
            if (currentGroupName == null || TextUtils.equals(currentGroupName, preGroupName))
                continue;
            //獲取需要操作的ItemDecoration的底部距離螢幕頂部的高度
            int viewBottom = view.getBottom();
            //決定當前頂部第一個懸浮ItemDecoration的bottom
            float bottom = Math.max(mGroupHeight, view.getTop());
            //下一XX省的ItemDecoration一步步逼近我們的首部的懸浮ItemDecoration
            if (position + 1 < itemCount) {
                //獲取下個GroupName(下一個XX省)
                String nextGroupName = getGroupName(position + 1);
                //下一組的第一個View(ItemDecoration)接近頭部
                if (!currentGroupName.equals(nextGroupName) && viewBottom < bottom) {
                    //bottom最小等於mGroupHeight,而當viewBottom(view.getBottom())小於bottom時,說明當前首都懸浮的ItemDecoration已經被擠壓。不斷更新bottom值。(因為我們繪製它時需要座標資訊,也就是這個bottom)
                    bottom = viewBottom;
                }
            }
            //根據bottom繪製ItemDecoration
            c.drawRect(left, bottom - mGroupHeight, right, bottom, mGroutPaint);
            Paint.FontMetrics fm = mTextPaint.getFontMetrics();
            //文字豎直居中顯示
            float baseLine = bottom - (mGroupHeight - (fm.bottom - fm.top)) / 2 - fm.bottom;
            c.drawText(currentGroupName, left + mLeftMargin, baseLine, mTextPaint);
        }
    }

大概上邊的過程看起來很複雜。其實如果理順了還是很好理解的:

1、我們需要的是繪製我們的XX省的ItemDecoration,因此我們不要判斷方式,這裡我是通過外部資料來源的方式去判斷(每個人可能會有不同的處理思路)。

2、然後在onDrawOver()方法中通過我們的處理思路,遍歷所有的View,針對我們要處理的ItemDecoration進行相關繪製。(這裡因為,我們使用getItemOffsets()已經為我們的ItemDecoration移好位置了),通過判斷view的getTop,getBottom,mGroupHeight等進行判斷是否倆個ItemDecoration進行碰撞,(具體思想可以回過去理解原始碼),不斷記錄bottom的值。

3、最後進行正常的Canvas繪製即可。

尾聲

理解之後實現起來還是比較的簡單。主要還是這種思維模式吧,怎麼去理解ItemDecoration分隔符的作用。
明天就要結束假期開始工作了,希望一切順利!

相關推薦

ItemDecoration實現固定浮式Item思路

寫在前面 這個國慶好像啥事都沒有做就已經過去,為了避免整個國慶的渾渾噩噩。那就在國慶的尾巴之時學一下習,記一個知識點。關於ItemDecoration的作用。在很久之前,我一直把ItemDecoration定義在僅僅是畫Item的分隔線。 然而當我看

RecyclerView.ItemDecoration實現佔位Item

RecyclerView.ItemDecoration實現佔位Item 一、為什麼需要佔位Item 二、實現效果 三、實現原理 四、完整程式碼 五、核心程式碼 六、下載地址 一、為什麼需要佔

bootstrap table 實現固定懸浮table 表頭並可以水平滾動

app 實現 question get net width class pan eight 在開發項目中,需要將表格頭部固定,而且表格大多數情況下是會水平滾動的。項目的css框架是bootstrap 3,故也可以叫做bootstrap table。 需要實現的是:表格頭部

RecycleView實現側滑刪除item

以及 urn 接口 add 是個 pre ack 編寫 ner 對於列表空間的側滑操作,網上有很多開源的空間可以使用,Google在它的新控件RecycleView中增加了側滑的API,完全遵循Material Design設計規範,下面看看效果演示: 下面看

Scrapy基礎————將不定長度的URL進行固定長度寫入Item

util img dig style lib 定義 項目 不存在 spa 前面講到將每篇文章的URL寫入Item,但是每個url的長度是不同的,可以在Item中設置一個字段怎樣使得每個URL的長度相同,這就需要對每個URL進行md5運算,使得長度統一,再加入到設定的It

duilib 實現 XML重用(item完全重合的CList)

顯示 界面 call 處理 vertica create ges ica 控件 最近做一個項目,界面庫用的是duilib。 軟件首頁的左側是一個機型列表,右側是機型信息及其他信息,點擊左側的機型,右邊跟著變為對應的信息。 由於右側信息比較復雜,還有進度條什麽的,所以如果右

多層交換機 實現不同網段 互通 思路解析

多層交換機 vlan 實驗名稱:多層交換機 實現不同網段 互通 思路解析實驗需求: ⑴ 三層交換 1,2,3,4 分別是vlan10,20,30,40的網關 (網關IP - 192.168.X.250/24) vlan 10 192.1

docker虛擬網橋實現固定IP,容器互通,外網可用

docker 虛擬化 網橋 centos 容器服務 提示:Docker不再兼容CentOS6,在使用docker的時候請將系統進行升級CentOS最低版本7.0 kernel最低3.10.0註意關閉SElinux和iptables等防火墻一、更新阿裏雲CentOS源,安裝Docker備

Python實現:楊輝三角思路

inpu pri 特點 png 組合 之一 targe pytho image 楊輝三角有以下幾個特點 : 每個數等於它上方兩數之和。 每行數字左右對稱,由1開始逐漸變大。 第n行的數字有n項。 第n行數字和為2n-1。 第n行的m個數可表示為 C(n

通過js實現固定表格的表頭和某列

通過js實現固定表格的表頭和某列 在開發過程中,如果資料比較多並且需要對比檢視的情況下,一般是是需要固定表頭和開始的某幾列。可以通過一些元件進行實現。但是引用元件需要引入大量的js檔案或者不滿足某一方面的需求。這時候就需要自己動手寫一個這樣的效果。 需求 表格是頁面的主體部分,表格的資料量比較大,需要

Android使用RecycleView實現拖拽交換item位置

本文例項為大家分享了RecycleView實現拖拽交換item位置的具體程式碼,供大家參考,具體內容如下 老規矩,先來一張效果圖: 相比起ListView而言,RecycleView實現拖拽交換位置的效果要簡單很多,因為通過SDK中的ItemTouchHelper工具類可以輕鬆的實現這

通過js手工實現 固定表格的表頭和固定

通過js實現固定表格的表頭和某列 在開發過程中,如果資料比較多並且需要對比檢視的情況下,一般是是需要固定表頭和開始的某幾列。可以通過一些元件進行實現。但是引用元件需要引入大量的js檔案或者不滿足某一方面的需求。這時候就需要自己動手寫一個這樣的效果。 需求 表格是頁面的主體部分,表

ItemDecoration詳解以及用ItemDecoration實現按字母排序列表

首先看看實現的效果 可以看出要實現上面效果,有三個步驟: 1.漢字轉化為拼音,並且根據首字母排序 2.用ItemDecoration實現字母行的顯示 3.自定義實現右側的按字母導航欄 當然重點講講ItemDecoration的實現。都知道RecyclerView本

css3實現固定表格頭部而無需設定單元格td的寬度

背景 最近小弟在工作都是做後臺系統,一堆的表格,各種各樣的。然後需求上要有固定的表頭的表格,如下圖所示 在網上查詢固定表頭的實現方式為: thead 設定為 fixed 拆分表格為兩個表格 thead一個,tbody一個 ​然而上面

利用ItemDecoration實現懸浮頭部

在我們的日常開發中,RecyclerView已經被使用的越來越廣泛,今天來講一講使用ItemDecoration來實現專案中需要的懸浮頭部的效果。我們使用listView就可以知道,直接從xml檔案中使用 android:divider 這個屬性就可以直接設定listVie中

iOS使用UIScrollView實現圖片迴圈滑動的思路解析

一組圖片迴圈滑動在開發中經常用到,App的歡迎頁、廣告banner等等都會用到。成熟的第三方也比較多,個人用的比較多的是JCTopic,這個很輕量級,程式碼也不多,用起來也是比較方便。 看過原始碼之後整理了一下實現的思路和原理,我們先來分析一下我們要實現的這個功能——圖片迴圈輪播,看到

陣列實現固定大小佇列和棧

棧的資料結構是先進後出,佇列的資料結構是先進先出。 陣列實現固定大小棧的思想是:先建立一個固定大小的陣列和一個size為0的常數,這個常數用來判斷棧是否滿或者空。當push時,檢視size的大小是否為大於陣列的長度,大於就給使用者拋異常,否則就插入陣列的size位置,siz

Java實現希爾排序(思路實現

希爾排序希爾排序(Shell Sort)是插入排序的一種。也稱縮小增量排序,是直接插入排序演算法的一種更高效的改進版本。希爾排序是非穩定排序演算法。該方法因DL.Shell於1959年提出而得名。 希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序;隨著增

使用陣列實現固定大小的棧結構

使用陣列實現固定大小的棧,很簡單,水一水。入棧規則:使用一個指標指向棧內元素的上一個位置,如果入棧,只需要在指標位置放入元素即可,然後指標再指向上一個位置,如果超出陣列長度,則報錯出棧規則:返回指標指向

vue表格實現固定表頭首列

前言 最近在做vue移動端專案,需要做一個可以固定表頭首列的表格,而且由於一些原因不能使用任何UI外掛,網上找了很久也沒什麼好方法,所以在解決了問題之後,寫下了這篇文章供後來人參考,文章有什麼錯漏的問題歡迎評論交流。 效果 思路 要實現固定首行首列 除了使用各種UI框架外掛外,那就是自己用原生寫啦