HELLO大神們,小弟初學Flutter有個問題:
在view的檔案裡因為有 Widget build(BuildContext context) 所以能很方便的取得context來使用,但小弟現在想要在一個外部的class直接取用context故採用此navigatorKey.currentContext以便在任何位置取用context,不果我發現似乎這樣取得的context和 Widget build 附帶的context有點不同,根據print出來的東西判斷:
從一個statefull class呼叫的context:_myClassName(dependencies: [MediaQuery], state: _myClassName#b89b3)
從navigatorKey.currentContext叫出來的context:Navigator-[LabeledGlobalKey<NavigatorState>#4bbf2](dependencies: [HeroControllerScope, UnmanagedRestorationScope], state: NavigatorState#3c029(tickers: tracking 1 ticker))
從print的結構即可看出這應該是不同的context,我認為是這部分導致了我無法正確取用這個功能(code如下):
(如果把'NavigationService.navigatorKey.currentContext' 換成來自 Widget build 的context就成順利運作)
FlutterToastr.show(
'MSG: King of flevor',
NavigationService.navigatorKey.currentContext,
duration: FlutterToastr.lengthLong,
position: FlutterToastr.bottom,
backgroundRadius: 32
);
請問有人知道如何解決此問題嗎? (使用環境: flutter stable 3.0.5)
其實只要追蹤一下你使用的FlutterToastr套件就可以得知問題所在。
原始碼54行中,作者利用context取得OverlayState。
overlayState = Overlay.of(context, rootOverlay: rootNavigator ?? false);
繼續檢查Overlay後會發現實際上是由Navigator所創建。
而Navigator往上就是WidgetsApp及MaterialApp。
能看出階層關係是:MaterialApp > WidgetsApp > Navigator > Overlay
接下來檢查關鍵的Overlay.of中是如何靠context取得OverlayState。
可以看到原始碼中是使用findRootAncestorStateOfType或findAncestorStateOfType。
final OverlayState? result = rootOverlay
? context.findRootAncestorStateOfType<OverlayState>()
: context.findAncestorStateOfType<OverlayState>();
至此就能發現問題所在,原因在於findRootAncestorStateOfType及findAncestorStateOfType實際上都是依照context在樹中的位置往上搜尋。
所以navigatorKey.currentContext所得到的context階層在Navigator,往上搜尋只有WidgetsApp及MaterialApp,導致套件中使用Overlay.of無法取得OverlayState。
建議除了使用Navigator外,盡量不要直接使用navigatorKey.currentContext。
而是配合架構改用當下顯示Widget的context。
如真的堅持要任何地方都可以用到的context的話,可以考慮在你的MainPage使用GlobalKey。