1. 程式人生 > >Flutter 中由 BuildContext 引發的血案

Flutter 中由 BuildContext 引發的血案

今天和各位分享一個博主在實際開發中遇到的問題,以及解決方法。廢話不多說,我們先來看需求: 我們要做一個iOS風格的底部選單彈出元件,具體涉及showCupertinoModalPopup()方法,該方法被執行後,會出現如下圖類似所示的選單彈出檢視: ![](https://img2020.cnblogs.com/blog/1595922/202006/1595922-20200613103427590-2032031849.png) 相信這個彈出選單檢視都有見過吧?下面重點來了:在本次的專案需求中,該檢視的**選項文字是由Server端返回**的。也就是說,這些選項的內容和個數都不固定,因此不能將其在程式碼中寫固定值。 為了簡化程式碼以突出重點,下面放上我在一開始的實現方案: ``` openActionSheet() { List menuWidgets = new List(); menuItems.forEach((element) { menuWidgets.add(CupertinoActionSheetAction( child: Text(element), onPressed: () { Navigator.pop(context); debugPrint("操作$element被執行“); }, isDefaultAction: true, )); }); showCupertinoModalPopup( context: context, builder: (buildContext) { return CupertinoActionSheet( title: Text('測試選單'), message: Text('點選選單項試試吧!'), actions: menuWidgets); }); } ``` 如上述程式碼所示,openActionSheet()是顯示該元件的方法。其中,showCupertinoModalPopup()為Flutter SDK內建方法,其作用即顯示這個元件;再其上面的迴圈以及List宣告、賦值等操作實際上就是在動態新增選單項。menuItems型別是List\。 通過對程式碼的解釋,相信大家能夠一目瞭然地看出,當某個選單項被點選時,整個選單元件消失,並列印Debug Log(對應為真實專案要執行的操作)。 大家覺得上述程式碼有問題嗎?如果有問題,問題在哪兒呢? 現在公佈答案:這段程式碼有問題! 上述程式碼執行時,當用戶點選選單項後,其執行結果並非如我們預想的那樣:選單組消失並輸出Log,而變成了:整個頁面被Pop,選單組保留,並輸出Log! 這是什麼原因呢? 實際上,罪魁禍首就在我們迴圈遍歷賦值操作時的這條語句: ``` Navigator.pop(context); ``` 這裡的context是整個頁面的BuildContext,而非選單組的。這裡我們要明確一個概念——我們想Pop誰,一定要用誰的BuildContext物件。 在這裡,正確的BuildContext物件是誰呢?它在這裡: ``` showCupertinoModalPopup( context: context, builder: (buildContext) { return CupertinoActionSheet( title: Text('測試選單'), message: Text('點選選單項試試吧!'), actions: menuWidgets); } ); ``` 注意到了嗎?上面第三行括號裡的buildContext才是我們真正要用的物件。因此,正確的做法是什麼呢? ``` openActionSheet() { BuildContext tempContext; List menuWidgets = new List(); menuItems.forEach((element) { menuWidgets.add(CupertinoActionSheetAction( child: Text(element), onPressed: () { Navigator.pop(tempContext); debugPrint("操作$element被執行"); }, isDefaultAction: true, )); }); showCupertinoModalPopup( context: context, builder: (buildContext) { tempContext = buildContext; return CupertinoActionSheet( title: Text('測試選單'), message: Text('點選選單項試試吧!'), actions: menuWidgets); }); } ``` 如上所示,我們只需將正確的物件“帶”到其作用域外面就可以了。 好了,這就是本篇文章的全部內容,希望能夠對你有所