【Flutter】自定義ListView開發記錄(五)—— 提供手勢等資訊

語言: CN / TW / HK

theme: condensed-night-purple

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

前言

前面基本完成了實現閱讀器所需的修改;現在還差一部分,提供出來當前ListView的index、手勢位置等資訊,以供item頁面使用(模擬翻頁);

思路

為了降低侵入性,我計劃打算通過 在 ListView 的 Scrollable 外面套一層 PrimaryScrollController ,在其中存放儲存資料的 ChangeNotify ;這樣由於 Item所在的Widget 均在ListView的 Widget樹中,自然可以通過 of方法獲取到,並獲取到需要的 ChangeNotify 中的資料;

另外用這種方式,知道自己展示內容的SliverList,也可以在特定時機,把一些當前 child擁有的parentData傳上去;這些parentData包含了index、scrollOffset 等資訊,還是挺有用的;

而且對於Item來說,可以通過諸如 addListener(markNeedsLayout) 這種方式,方便的觸發手勢響應;

實現

這塊的實現其實也很簡單,最簡陋的實現如下:

image.png

image.png

image.png

然後重寫ListView的build方法:

image.png

至於如何去使用這個,就要涉及到另一部分了;

首先,因為只有模擬翻頁才會使用到這裡提供的手勢資訊,所以以模擬翻頁為例:

(請自覺無視掉其中令人瞎眼的測試頁,以及僅僅完成了部分模擬翻頁效果,還有莫名其妙的Item位移)

image.png

可以看到,需要對 Item本身進行裁剪,這就要涉及到對canvas進行操作;一提到這個,自然想到的控制元件就是CustomPaint了;

但是經過研究,我發現CustomPaint僅僅提供了再canvas繪製前和繪製後的操作;

另外如果對canvas擦除清空(我使用的是 canvas.drawColor(Colors.red, BlendMode.clear); 不知道還有沒有其他的擦除方式),按照本來的設想,應該是透明頁面才對,然而最終效果不是透明,而是黑色……

最後再github issue區發現一種解決方式:

image.png

https://github.com/flutter/flutter/issues/24466#issuecomment-439611100

不過要實現這種效果,就需要自定義CustomPaint了;不過因此也能參考CustomPaint的方式,自動給手勢新增markNeedPaint;

最終的粗略版自定義實現部分:

image.png

應該還有不少可以優化的地方,如果能解決那個黑色的問題,或許就可以避免使用saveLayer這種不推薦的實現方式;

結語

自此,對小說閱讀器所需的部分,都已經實現出來了;

接下來或許就可以通過自定義的ListView來實現一個小說閱讀器;這樣不僅能擺脫canvas部分的限制,自由的佈局和使用已經提供的widget;而且可以讓Item部分拆離開來,更加註重自身實現,而非像canvas實現方式那樣,一個canvas繪製了所有部分;

「其他文章」