隨著 Flutter 3.3 正式版發布,Global Selection 終于有了官方的正式支持,「該功能補全了 Flutter 長時間存在 Selection 異常等問題,特別是在 Flutter Web 下經常會有選擇文本時與預期的行為不匹配的情況」。
使用
「使用 SelectionArea 也十分簡單,如下代碼所示,只需要在您想要支持的地方添加 SelectionArea 即可」,甚至可以在每個路由下的Scaffold 添加SelectionArea 來全面啟用支持。
默認情況下SelectionArea 已經實現了所有常見的功能,并且 Flutter 針對不同平臺進行了差異化實現,如下圖所示 Android 和 iOS 會有不同的樣式效果。
所以如果您覺得這個判斷有問題,完全可以自己 override 一個自定義的 TextSelectionControls,比如在canSelectAll 直接 return true。
是的,「對于SelectionArea 我們可以通過繼承 TextSelectionControls 來自定義」:
通過 buildToolbar 自定義彈出的 Toolbar 樣式和邏輯,甚至您可以添加一些額外的標簽能力,比如 "插入圖片"; 通過 buildHandle 自定義 Selection Handle 可拖動部分的樣式。
而在SelectionArea 里,不管是 Handle 還是 Toolbar,都是通過新增 Overlay 來實現樣式,這部分的邏輯主要在 SelectionOverlay 對象:
如果您還不了解Overlay,可以簡單理解為:「默認情況下所有的路由頁面都在一個 Overlay 下,打開一個 Route 就是添加一個 OverlayEntry 到 Overlay 里」。
所以 Handle 和 Toolbar 都是通過OverlayEntry 打開的特殊 "路由" 控件,擁有新的層級,例如下方右圖就是 Toolbar 所在的OverlayEntry。
「另外,對于 Handle 的顏色定義,默認情況下主要來自 TextSelectionTheme 和Theme」。
例如MaterialTextSelectionControls 里,start 和 end 兩個 Handle 的顏色,默認是通過 TextSelectionTheme 的 selectionHandleColor 或者Theme 的primary 來設置。
而對于文字的選中區塊的顏色,默認是通過 DefaultSelectionStyle 的 selectionColor 來顯示,當然,如下第二張圖所示,在 MaterialApp 里它依然和 TextSelectionTheme 的 selectionColor 或者Theme 的primary 有關系。
「那如果您還想要在SelectionArea 下的某些內容不允許被選中呢」?
這里 Flutter 提供了 SelectionContainer.disabled 實現,只要在對應內容嵌套 SelectionContainer.disabled,那么這部分內容下的文本就無法被選中。
為什么嵌套SelectionContainer.disabled 就可以禁用文本選中的能力?這其實和SelectionArea 的實現有關系:
SelectionContainer 內部實現了一個 InheritedWidget,它會往下共享一個 SelectionRegistrar,而默認情況下SelectionArea 內部使用了SelectionContainer 并且往下共享了對應的 Registrar 實現。
SelectionArea 內部的 SelectionContainer 是有對應的 registrar 實現往下共享; SelectionContainer.disabled 內部的registrar 是 null。
△圖二
到這里您應該大致理解了如何使用和自定義一些 SelectionArea 的能力,那么接下來介紹兩個 "Bug",通過這兩個 "Bug" 我們深入理解SelectionArea 內部的實現情況。
問題 1
如下代碼所示,「當使用了WidgetSpan 之后,默認情況下,用戶在開始位置拖拽 Handle 進行選擇時會無法選中WidgetSpan 里的文本」。
PS:其實拖動可以選中,只是這里暫時以不能選中的情況下作為切入點。
當然,「其實在拖動Handle還是可以選中WidgetSpan里的文本,比如您從HelloWorld開始拖動,這里拖動選中不了的原因后面會解釋」。
問題2
如果當我們點擊了全選會怎么樣?如下圖所示,在我們點擊全選之后,可以看到兩個 "奇怪" 的問題:
WidgetSpan 里的 Hello World 可以被選中了; 左側的 Start Handle 位置不是在文本開頭,而是在WidgetSpan 開始。
我們首先看第一點,「為什么點擊全選時,WidgetSpan 里的 Hello World 可以被選中」?
其實全選操作和拖拽 Handle 最大的不同就是: 它是往下直接發出全選事件 SelectAllSelectionEvent,而該事件會觸發所有 child 響應事件,自然也就包括了 WidgetSpan 里的 Hello World。
_handleSelectAll 獲取得到 _textSelectionStart 和 _textSelectionEnd,表明此時控件已經被選中; didChangeSelection 里通過 paragraph.markNeedsPaint() 觸發重繪,然后增加選中時的覆蓋顏色。
首先我們看,為什么復制出來之后的內容會是Hello World!Flutter isthe best!?
正如前面說到的,復制調用的是 getSelectedContent 方法,如下代碼所示,「可以看到在selectables 這個 List 的第一位就是Hello World,所以最終拼接出來的文本會是Hello World!Flutter isthe best!」 。
目前這個問題在 master 和 stable 分支均可以復現,對應 issue 我也提交在#111021。
最后
雖然SelectionArea 的出現補全了 Flutter 的長久以來的短板之一,不過基于SelectionArea 實現的復雜程度,目前SelectionArea 還有不少的細節需要優化,但是萬事開頭難,本次 3.3 SelectionArea 的落地也算是一個不錯的開始。
最后,相信通過本文大家應該對 SelectionArea 的使用和實現都有了一定的了解。
長按右側二維碼
查看更多開發者精彩分享
"開發者說·DTalk" 面向中國開發者們征集 Google 移動應用 (apps & games)?相關的產品/技術內容。歡迎大家前來分享您對移動應用的行業洞察或見解、移動開發過程中的心得或新發現、以及應用出海的實戰經驗總結和相關產品的使用反饋等。我們由衷地希望可以給這些出眾的中國開發者們提供更好展現自己、充分發揮自己特長的平臺。我們將通過大家的技術內容著重選出優秀案例進行谷歌開發技術專家 (GDE)的推薦。
?點擊屏末|閱讀原文|即刻報名參與"開發者說·DTalk"
原文標題:Flutter 3.3 之 SelectionArea 好不好用?用 "Bug" 帶您全面了解它 | 開發者說·DTalk
文章出處:【微信公眾號:谷歌開發者】歡迎添加關注!文章轉載請注明出處。
-
谷歌
+關注
關注
27文章
6161瀏覽量
105304
原文標題:Flutter 3.3 之 SelectionArea 好不好用?用 "Bug" 帶您全面了解它 | 開發者說·DTalk
文章出處:【微信號:Google_Developers,微信公眾號:谷歌開發者】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論