Flutter很好用,but……

前言

爲何有這篇文章?java

這篇文章能夠說是我的Flutter問題隨筆吧,雖然Flutter能夠方便的作到跨平臺,可是畢竟是新項目,功能沒那麼全面也是意料之中,因此在此記錄跟蹤一下目前在使用Flutter過程當中遇到的問題,目前的解決方案,並跟蹤記錄一下。android

問題列表(持續更新):git

  1. Flutter 中不支持異步測繪大量文字
  2. Flutter IOS 後臺音頻播放
  3. Flutter 中 NestedScrollView 中存在摺疊頭、子列表等狀況下的滑動等異常
  4. Hero 跳轉以後的圖片若是在摺疊佈局中被摺疊隱藏了,那麼Hero的退出動畫沒法正常播放,而且原圖片沒法顯示(flutter的master分支已修復)
  5. listView 不支持按index跳轉

正文

1. Flutter 中不支持異步測繪大量文字

這個源自於我的練手APP,在開發閱讀模塊過程當中遇到了這麼一個問題:github

若是想要自定義文字間距,段落間距等,那麼天然就要使用textPainter本身繪製文字。可是由此引起出一個問題:若是有上萬個文字,那麼測繪時間會很長。天然會阻塞主進程。canvas

解決這個問題,第一個想法天然就是使用異步處理,那麼flutter 中的異步方案有哪些呢?緩存

  1. Future(包括await async那些東西)
  2. isoloate

按照官方文檔,大量計算東西應該放到Isolate中,因此,天然而然地,咱們將textPinter測繪方法放到Isolate中執行,可是呢,執行報錯:native function not foundbash

緣由就是UI包的類只容許在Flutter的UI Isolate中執行。服務器

此題無解,完結撒花,各回各家,各找各媽(纔怪)異步

解決方案一:Pluginasync

這個方法的思路來自於官方開發人員的回答:

right now you would have to write your own line-breaking logic - perhaps as a plugin. We don't currently have any API for doing text layout in a separate isolate. @GaryQian might have some other idea about this too.

因此說,咱們看下官方的Plugin是怎麼實現的。

在 Plugin工程中,有這麼一個: android_alarm_manager ,這個Plugin中的AlarmService.java文件中,有這麼一個方法:startBackgroundIsolate(要素察覺+1)

經過閱讀源碼,咱們得知,其實說白了就是新建一個FlutterNativeView ,這個FlutterNativeView 不負責渲染界面,只負責當後臺線程來用。一樣的道理,咱們也能夠用一樣的方法來處理咱們的須要運行在UI Isolate的異步任務。(至於爲何新建一個FlutterNativeView ,就能實現這個需求,粗略的說下是由於,每次新建FlutterNativeView,其實都會新建一些TaskRunner,其中就包含UI 的TaskRunner,總之有興趣的能夠搜下Flutter中的TaskRunner機制瞭解下)

不過,其實不用本身實現註冊,有這麼一個第三方:flutter_isolate能夠作到這點,用法跟普通的isolate差很少,因此解決方式也很簡單:找到原來使用Isolate的那段代碼,把Isolate.spawn替換爲FlutterIsolate.spawn便可。不過通過測試,在1.10版本上會報錯,因此想使用這個方式的話,仍是切回stable 分支使用吧。

解決方案二:分割爲多個小任務(我的感受不太推薦這種方式,感受不可控,畢竟假如小任務的執行時間也很長咋辦)

這種方式說白了就是每測繪完一行,就提交一次,而不是總體測繪完以後再提交結果。

舉個小例子:

Future(() async {
  var result;
  for (var i = 0; i < 1000000; ++i) {
    result = 'result is $i';
    await Future.delayed(Duration.zero);
  }
  print(result);
});
複製代碼

用這種方式計算就不會卡UI

解決方案三:目前這個問題已經加入到里程碑了,在將來的某天應該就有解決方案

github.com/flutter/flu…

2. Flutter IOS 後臺音頻播放

也就是像音樂播放器那樣,會有個通知顯示進度,即便在桌面也能夠播放音樂這種

目前只有Android的實現,IOS這塊目前尚未方案……%

3. Flutter 中 NestedScrollView 中存在摺疊頭、子列表等狀況下的滑動等異常

找了半天才發現有個大佬已經搞定了這個問題:

juejin.im/post/5bea43…

使用extended_nested_scroll_view便可解決這個問題,在此記錄一下

4. Hero 跳轉以後的圖片若是在摺疊佈局中被摺疊隱藏了,那麼Hero的退出動畫沒法正常播放,而且原圖片沒法顯示

這個描述可能有些抽象,具體狀況以一個例子爲例描述:

1、首頁放一個圖片,給他設置點擊跳轉詳情頁,並設置hero動畫。

2、將圖片設置爲SliverAppBar的FlexibleSpaceBar的widget中的內容,而後上拉頁面,摺疊隱藏掉SliverAppBar。

3、按後退鍵退出詳情頁,觸發hero的關閉動畫。

按這三步執行以後,首頁原來那張圖片就變成空白,並且沒法點擊。

issue:

github.com/flutter/flu…

github.com/flutter/flu…

因此切換到master分支或者dev分支(問題修復版本v.1.10.14),或者下降穩定版的版本。

5. listView 不支持按index跳轉

下面是我搜索出的內容:

stackoverflow.com/questions/5…

pub.dev/packages/in…

pub.dev/packages/sc…

pub.dev/packages/fl…

上面的實現方法各有千秋吧,整理一下主要的缺陷點,之後能夠根據實際狀況使用:

  1. stackOverflow 中提到了兩種方法:一是使用index_list_view,這個稍後統一分析。二是 gist.github.com/debuggerx01… ,不過有老哥將它放在帶評論的列表上,結果性能比較差,簡介文章中也講明瞭,若是處理很差確實可能存在性能問題。
  2. indexed_list_view stackOverflow中也提了,這個適用於無限列表的狀況。
  3. scroll_to_index 代碼稍微有點侵入性(其實這個不是重點),其次沒有jump方法,scroll時長好像也沒什麼效果,因此若是列表比較大而跳轉距離也很大(好比說凡人修仙傳的章節那種……),那麼動畫效果比較感人。(PS:好像這個滑動時間長的問題(github.com/flutter/flu…)已經修復了,雖然在這個issue中沒有說,可是我本身在v1.10.14上發現好像如今scroll動畫能在很短期內滑動到目標位置了)
  4. flutter_widgets 谷歌大大的產品(不過不是官方正式控件),基本知足需求,方法也很簡單,jump方法的什麼也有。可是,若是把它放到NestScrollView中搞視差滑動的頁面的時候,會致使總體沒法滑動,只能滑動ScrollablePositionedList中的內容……(其實緣由就是由於自定義了controller),並且若是存在ExpansionTile這種可伸縮的佈局,經過伸縮方式改變了item的高度,ScrollablePositionedList並不會更新高度,而是仍是以改變前高度爲準進行index跳轉。

如今正在嘗試解決ScrollablePositionedList中的視差滑動問題,(得想個辦法讓NestScrollView屆的到ScrollablePositionedList的controller) 在NestScrollView中是經過設置PrimaryScrollController,讓innerController管理body滑動的,因此使用這個innerController來替代ScrollablePositionedList的controller便可解決沒法滑動的問題,可是隨之而來的是一個新的問題,如今按index跳轉,會致使body觸發滑動,進而直接摺疊掉SliverAppBar……………如何讓index跳轉的時候,body在NestScrollView中的位置不動,只在原地實現自身的index跳轉,只有手動滑動的時候才容許改變body在NestScrollView中的位置,目前想法是在SliverAppBar的floating、pinned等控制滑動方式的方法上看看有沒有突破口。 不搞了,如今挺好的。直接滿屏展現,實在不行加個跳轉到頂部按鈕,我感受蠻合理的。(大霧)

改變高度這個,目前採用設置addPersistentFrameCallback 方式持續監聽。本覺得應該性能比較差,可是測試了一下,好像frame沒啥變化,因此應該沒啥問題。

題外話

有些同窗可能對我爲何須要測量上萬字感到困惑,因此在這簡單的提下:

測繪上萬字這個狀況來自於我想把本身原來的一個Android原生小說閱讀器,轉換爲flutter實現(主要是想實現那幫仿真、滾動等翻頁動畫啥的,練習一下flutter的canvas操做),小說閱讀器的基本思路參考自這個項目:任閱

思路基本是這樣的:

基本功能是:上一頁,下一頁,上一章,下一章,章內跳頁。

由於要考慮上一章下一章切換以及章內跳轉到多少頁的這些功能,因此天然以章爲基礎單位,章內部包含頁,取的時候把章的數據拿出來,而後從章中頁數據中取出要展現的頁的數據,並將其繪製到canvas上。

因此,緩存計算也是計算的章的內容,因此當從服務器下載下來新的章的時候,就有可能遇到上萬字的章的狀況。

可能也有同窗說:直接按頁緩存不就好了,每次只緩存幾頁的內容,那確定不會遇到須要一次性測量上萬字的狀況。可是若是純粹按頁緩存的話,若是遇到這兩種狀況就傻眼了:1. 若是有個用戶打開一本新的小說,直接跳到第十章,而後按了上一頁。 2. 章節內跳轉到第n頁(n>緩存頁數)。

由於標點符號、全角、特殊字符等非普通漢字的存在,因此咱們是沒法直接得知每頁展現的內容,天然沒法在測量完整章以前得知某頁的展現內容,因此要支持上面提到2個狀況,必然要測量分頁整章內容。

固然,可能我這個思路也不是最優解,若是有更好的方案,但願各位不吝指教

相關文章
相關標籤/搜索