【Flutter】自定義ListView開發記錄(四)—— 關於ParentData的設想和分析與簡單實踐

語言: CN / TW / HK

theme: condensed-night-purple

「這是我參與11月更文挑戰的第11天,活動詳情檢視:2021最後一次更文挑戰」。

前言

前面對hitTest方法進行了修改,以實現點選事件的處理;

但是肯定有人看出來了,這就是個治標不治本的方法,說白了,在整個SliverList流程中傳遞的資料並未修改,對於其他部分而言,它們還是根據資料,認為item按照ListView那種依次排列的方式進行的;

隨著後續自定義ListView功能的增多,這部分肯定會造成困擾和誤導;

那現在就來從資料來源的角度進行一下修改;

評估

首先,先來確認下ParentData中的資料和其作用:

SliverList中parentData是 SliverMultiBoxAdaptorParentData ,在其中存放的是 index 和 keepAlive ;作用嘛,字面意思:

image.png

其父類放的就是經常使用的layoutOffset引數:

image.png

還有兩個mixin,一個用來存放child連結串列關係:

image.png

另一個還是keepAlive相關……至於這個keepAlive和keptAlive有啥區別……好像沒區別,get都給重寫掉了……

image.png

現在要關注的是layoutOffset,起初我的想法是修改layoutOffset;但是layoutOffset所提供的作用不僅僅是為了表明位置,通過這個還能得知Item之間的相對位置關係;說白了就是能通過layoutOffset得知當前child前面多少多少是上一個child;

所以像現在這種,從lastChild往前遍歷的方式上,能知道各個child之前的相對位置關係;還是挺有必要的~畢竟firstChild 並不一定會顯示在ViewPort指定的可視範圍內,如果所有child的layoutOffset都是實際在canvas上的位置,那麼如何得知當前ScrollOffset對應哪些child呢;

糾結了一小段時間後,我發現,在原始碼中有這麼個一個變數:paintOffset;比如說這種:

image.png

既然原始碼中有這種東西,或許追蹤一下就知道怎麼搞了

有個讓我困惑的地方

首先還是先看註釋:

image.png

按照註釋說明,這東西正是我所需要的東西,用來體現child相對於parent位置的;

不過有個讓我有點疑惑的東西,在註釋中明確說明這東西最好用在僅有少量child的view上面;為啥這麼說呢,講道理設定個paintOffset,和設定layoutOffset沒太大區別吧,無非到時候根據scrollOffset計算一下而已;

檢視一下呼叫位置,確實正如註釋中說明的那樣,基本都是隻持有一個child的那種View在使用這個parentData;

其具體呼叫位置也是performLayout這塊;例如這樣:

image.png

其中一個呼叫位置是這樣的:

image.png

好像沒啥太複雜的計算,或者延時操作啊,為啥指定持有少量child的View呢?

設計

我設想的方案同樣是在performLayout 這塊,在計算了各個item的 layoutOffset的同時, 結合情況,將paintOffset也計算出來,以目前計劃實現的覆蓋翻頁為例:

image.png

那麼需要做的事就明確了:

  • 提供設定一個新的ParentData,用於儲存paintOffset;
  • 提供一個計算paintOffset的方法,提供給LayoutOffset;
  • 修改paint方法,改為根據paintOffset來繪製;
  • 修改hitTest方法,同樣改為根據paintOffset來計算;

參考原始碼,ctrl + CV戰士無所畏懼;

結尾

目前簡單測試了下,並未發現什麼效能損耗;所以註釋中那段確實讓我挺困惑的

「其他文章」