【Flutter】小說閱讀器改版 (二)—— 改進一下模擬翻頁的效果

語言: CN / TW / HK

theme: condensed-night-purple

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

前言

現在所需的ListView改造好了,可以去將ListView應用到小說閱讀器上;但是按照之前的實現,現在還需要實現一些準備部分;

要實現的效果:

首先,在之前的文中,僅僅實現了覆蓋翻頁的LayoutManager,模擬翻頁也需要一個,不過這次挑戰一下更模擬的模擬翻頁(參考小米閱讀App的模擬翻頁效果)

在之前專案中,前一頁的翻頁效果跟後一頁是一樣的,除了方向並無區別;

而在小米閱讀上,效果是從前往後翻到指定位置:

小米閱讀.gif

分析

要實現這種效果,我想有兩種思路:

  • 第一種:固定載入兩頁,當觸發手勢操作的時候,第一頁固定展示最頂層的效果;而不是固定展示最頂層的那頁(舉個例子,如果有1,2,3三頁,當前處於第二頁,往前翻的時候,第一頁展示的是第一頁,第二頁處於底部,展示第二頁的部分;但往後翻的時候,第一頁展示的是當前所看的第二頁的效果,第二頁展示第三頁的部分)

  • 第二種:固定內容跟Item繫結,結合ScrollController和其所持有的position,計算各種操作應該變化多少offset,再通過之前提供出來的手勢資訊,讓各個Item自己判斷是否要展示翻頁效果;(這種情況下舉例的話,應該是動態載入的兩頁,這兩頁繫結所展示的內容,還是之前的那個例子,往前翻,ListView先改變offset到特定位置,然後第一頁展示翻頁效果,第二頁展示第二頁;往後翻,第二頁展示第二頁的翻頁效果,第三頁就展示第三頁;)

第一種思路,就是之前通過canvas來實現的效果;優點就是省事,缺點嘛,也很明顯,各種頁面切換,不好上手理解;

第二種思路,就是我現在想實現的方式,優點就是讓Item只通過資料驅動,沒有什麼狀態切換之類的東西;缺點就是會複雜不少,畢竟要通過資料來驅動;而非直接修改;

實現:

以手勢操作開始分析:

  • 因為僅僅是移動的時候生效,所以很明顯是move事件觸發的,那麼如果我 move 事件觸發的時候,將Item移動到指標所在的位置,然後Item繪製翻頁效果的時候,指標的橫向座標使用offset偏移量,縱向還是用指標的縱座標,這種方式是否可以呢?

將Item移動到指定位置,可以通過ScrollController的 animateTo 方式來實現;

之前的分析中也說明了,可以通過 Controller 來獲取 position ,裡面儲存了包括偏移量,Item寬度等資訊,這樣也可以計算出要移動到的位置;

看上去好像沒什麼問題?

做個小型demo實驗一下,為了方便看出效果,以覆蓋翻頁的layoutManager為例,並僅僅計算處理一次move事件簡單驗證下:

QQ20211122-202229-HD.gif

確實是可以在move事件中呼叫animateTo方法改變offset;但是也發現一個問題,後續的拖動事件全部失效~

原因嘛,是因為animateTo方法會呼叫beginActivity,這個新的activity是 DrivenScrollActivity ,因為呼叫了新的activity,drag的activity會被中斷銷燬:

image.png

但是drag僅僅在dragStart的時候建立,所以後續的move事件呼叫不到drag來處理,自然沒有效果~~~

image.png

image.png

結尾

看來要想以第二種方式來實現小米閱讀的效果;也沒那麼輕鬆,接下來的想法是對 ScrollActivity 進行處理;如果在現在的效果上,能不中斷drag,自然所有問題就能解決,接下來我會先嚐試以下兩個方法:

  • 自定義ScrollActivity,接管drag和那個負責animatedTo的DrivenScrollActivity?這樣他倆都是一個東西,自然不會衝突銷燬;
  • 對beginActivity進行修改,讓其在特定條件下不去銷燬drag;通過優先順序來對任務排程;
  • 自己看看能否實現一個新的animatedTo方法,通過不斷模擬drag事件的方式來觸發;
「其他文章」