Flutter 中由 BuildContext 引發的血案


今天和各位分享一個博主在實際開發中遇到的問題,以及解決方法。廢話不多說,我們先來看需求:
我們要做一個iOS風格的底部菜單彈出組件,具體涉及showCupertinoModalPopup()方法,該方法被執行后,會出現如下圖類似所示的菜單彈出視圖:

相信這個彈出菜單視圖都有見過吧?下面重點來了:在本次的項目需求中,該視圖的選項文字是由Server端返回的。也就是說,這些選項的內容和個數都不固定,因此不能將其在代碼中寫固定值。
為了簡化代碼以突出重點,下面放上我在一開始的實現方案:

  openActionSheet() {
    List<Widget> 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<String>。
通過對代碼的解釋,相信大家能夠一目了然地看出,當某個菜單項被點擊時,整個菜單組件消失,並打印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<Widget> 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);
        });
  }

如上所示,我們只需將正確的對象“帶”到其作用域外面就可以了。
好了,這就是本篇文章的全部內容,希望能夠對你有所幫助!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM