Flutter 里的 BuildContext 相信大家都不會陌生,雖然它叫 Context,但是它實際是 Element 的抽象對象,而在 Flutter 里,它主要來自于 ComponentElement 。
成都創新互聯專業為企業提供江南網站建設、江南做網站、江南網站設計、江南網站制作等企業網站建設、網頁設計與制作、江南企業網站模板建站服務,十余年江南做網站經驗,不只是建網站,更提供有價值的思路和整體網絡服務。
關于 ComponentElement 可以簡單介紹一下,在 Flutter 里根據 Element 可以簡單地被歸納為兩類:
所以一般情況下,我們在 build 方法或者 State 里獲取到的 BuildContext 其實就是 ComponentElement 。
那使用 BuildContext 有什么需要注意的問題 ?
首先如下代碼所示,在該例子里當用戶點擊 FloatingActionButton 的時候,代碼里做了一個 2秒的延遲,然后才調用 pop 退出當前頁面。
正常情況下是不會有什么問題,但是當用戶在點擊了 FloatingActionButton 之后,又馬上點擊了 AppBar 返回退出應用,這時候就會出現以下的錯誤提示。
可以看到此時 log 說,Widget 對應的 Element 已經不在了,因為在 Navigator.of(context) 被調用時, context 對應的 Element 已經隨著我們的退出銷毀。
一般情況下處理這個問題也很簡單, 那就是增加 mounted 判斷,通過 mounted 判斷就可以避免上述的錯誤 。
上面代碼里的 mounted 標識位來自于 State , 因為 State 是依附于 Element 創建,所以它可以感知 Element 的生命周期 ,例如 mounted 就是判斷 _element != null; 。
那么到這里我們收獲了一個小技巧: 使用 BuildContext 時,在必須時我們需要通過 mounted 來保證它的有效性 。
那么單純使用 mounted 就可以滿足 context 優化的要求了嗎 ?
如下代碼所示,在這個例子里:
由于在 5 秒之內,Item 被劃出了屏幕,所以對應的 Elment 其實是被釋放了,從而由于 mounted 判斷, SnackBar 不會被彈出。
那如果假設需要在開發時展示點擊數據上報的結果,也就是 Item 被釋放了還需要彈出,這時候需要如何處理 ?
我們知道不管是 ScaffoldMessenger.of(context) 還是 Navigator.of(context) ,它本質還是通過 context 去往上查找對應的 InheritedWidget 泛型,所以其實我們可以提前獲取。
所以,如下代碼所示,在 Future.delayed 之前我們就通過 ScaffoldMessenger.of(context); 獲取到 sm 對象,之后就算你直接退出當前的列表頁面,5秒過后 SnackBar 也能正常彈出。
為什么頁面銷毀了,但是 SnackBar 還能正常彈出 ?
因為此時通過 of(context); 獲取到的 ScaffoldMessenger 是存在 MaterialApp 里,所以就算頁面銷毀了也不影響 SnackBar 的執行。
但是如果我們修改例子,如下代碼所示,在 Scaffold 上面多嵌套一個 ScaffoldMessenger ,這時候在 Item 里通過 ScaffoldMessenger.of(context) 獲取到的就會是當前頁面下的 ScaffoldMessenger 。
這種情況下我們只能保證Item 不可見的時候 SnackBar 還能正常彈出, 而如果這時候我們直接退出頁面,還是會出現以下的錯誤提示,因為 ScaffoldMessenger 也被銷毀了 。
所以到這里我們收獲第二個小技巧: 在異步操作里使用 of(context) ,可以提前獲取,之后再做異步操作,這樣可以盡量保證流程可以完整執行 。
既然我們說到通過 of(context) 去獲取上層共享往下共享的 InheritedWidget ,那在哪里獲取就比較好 ?
還記得前面的 log 嗎?在第一個例子出錯時,log 里就提示了一個方法,也就是 State 的 didChangeDependencies 方法。
為什么是官方會建議在這個方法里去調用 of(context) ?
首先前面我們一直說,通過 of(context) 獲取到的是 InheritedWidget ,而 當 InheritedWidget 發生改變時,就是通過觸發綁定過的 Element 里 State 的 didChangeDependencies 來觸發更新, 所以在 didChangeDependencies 里調用 of(context) 有較好的因果關系 。
那我能在 initState 里提前調用嗎 ?
當然不行,首先如果在 initState 直接調用如 ScaffoldMessenger.of(context).showSnackBar 方法,就會看到以下的錯誤提示。
這是因為 Element 里會判斷此時的 _StateLifecycle 狀態,如果此時是 _StateLifecycle.created 或者 _StateLifecycle.defunct ,也就是在 initState 和 dispose ,是不允許執行 of(context) 操作。
當然,如果你硬是想在 initState 下調用也行,增加一個 Future 執行就可以成功執行
那我在 build 里直接調用不行嗎 ?
直接在 build 里調用肯定可以,雖然 build 會被比較頻繁執行,但是 of(context) 操作其實就是在一個 map 里通過 key - value 獲取泛型對象,所以對性能不會有太大的影響。
真正對性能有影響的是 of(context) 的綁定數量和獲取到對象之后的自定義邏輯 ,例如你通過 MediaQuery.of(context).size 獲取到屏幕大小之后,通過一系列復雜計算來定位你的控件。
例如上面這段代碼,可能會導致鍵盤在彈出的時候,雖然當前頁面并沒有完全展示,但是也會導致你的控件不斷重新計算從而出現卡頓。
所以到這里我們又收獲了一個小技巧: 對于 of(context) 的相關操作邏輯,可以盡量放到 didChangeDependencies 里去處理 。
先制作一個縱軸滾動的pageview
然后我們利用time組件實現自動輪播,這里面有個小技巧,掌握了這個小技巧就可以做無縫的循環播放,比如我有 a b c三項,我們在構造pageview item的時候人為的構造成a b c a,在c的后面加上a,當c滾動到a的時候,比如每次動畫變換時間是500毫秒,那么就延遲500好秒快速的跳到第一個a頁面,剛好等它滾動完就快速變換
在視覺上完全看不出來,這樣就造成了無縫循環滾動的假象,同理如果你想反方向也可以無縫循環滾動,那么你在構造pageview item的時候就可以 這樣c a b c a構造,只要控制好邏輯,完全沒有任何問題
針對日常不同的需求,我們時常需要自定義 Dialog ,而小菜在嘗試過程中遇到一些小問題,簡單記錄總結一下;
小菜在自定義含有文本框的 Dialog 時,文本框獲取焦點時,軟鍵盤會部分遮擋對話框,但當小菜替換為 AlertDialog 時,文本框獲取焦點時,對話框會向上浮動,避免軟鍵盤遮擋;
對于含有文本框的自定義 Dialog ,小菜在最外層使用的是 Material 嵌套,小菜通過采用 Scaffold 來嵌套處理,默認 Scaffold 中 resizeToAvoidBottomPadding / resizeToAvoidBottomInset 為 true ,當設置為 false 時,文本框獲取焦點時,依舊會被軟鍵盤遮擋;因為在固定情景可以配合 resizeToAvoidBottomPadding 實現是否被軟鍵盤遮擋效果;
resizeToAvoidBottomPadding 主要用于自身 Widget 是否避免被其他窗口遮擋;其中小菜查資料介紹在 Flutter 1.1.9 之后更推薦使用 resizeToAvoidBottomInset ;
小菜自定義一個可以多選 item 的 Dialog ,但 Dialog 中并沒有狀態更新的 State ,如何進行 Dialog 中狀態更新呢?
小菜之前在 showDialog 時直接創建了 TypeListDialog ,此時是無狀態的,當 WidgetBuilder 創建一個 StatefulBuilder 有狀態的構造器即可,可以將 state 傳遞到 Dialog 中;
小菜在自定義 Dialog 時如何在一個回調方法中傳遞多個參數?
小菜在 Dialog 的回調方法中傳遞兩個 List ,而在接收回調方法中匹配兩個參數即可;小菜簡單看作是一個函數方法;
小菜在重寫 AppBar 時,如何取消默認的返回按鈕?
取消 AppBar 前面的返回圖標有多種方式;
自定義 Dialog 案例源碼
小菜對于 Flutter 的應用還不夠熟悉,很多常用的場景會處理的很不到位,小菜會對日常的小問題進行簡單記錄,逐步學習;如有錯誤,請多多指導!
標題名稱:flutter小技巧,flutter入門教程
瀏覽地址:http://vcdvsql.cn/article16/dsdiidg.html
成都網站建設公司_創新互聯,為您提供用戶體驗、商城網站、Google、網站設計、微信小程序、軟件開發
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯