Flutterでシンプルなタブバーベースのアプリを作っています。と を使用CupertinoTabScaffold
しCupertinoTabBar
ます。それぞれCupertinoTabView
に独自の がありWebView
ます。
最初のには、クリックすると選択したタブが次のタブに変更され、ウィジェットを含むTabView
をロードし、特定の Web サイトの URL に移動するボタンが配置されます (URL は に書かれているのではなく、最初のタブから取得されることに注意してください)タブ)。CupertinoTabView
WebView
WebView:initialURL
問題は、コントローラーが割り当てられていないため、選択したタブが変更されている間にボタンをクリックするとWebView
、特定の URL がロードされないことです。WebView
CupertinoTabView
新しいウィジェットが完全に読み込まれるまでアプリを「待機」させるにはどうすればよいですか?
アプリを実行すると、エラーは次のようになります。
Unhandled Exception: NoSuchMethodError: The method 'navigateTo' was called on null.
これは、ボタンをクリックして次のコードを実行すると、行 tabController.index = tabIndex
が有効になる前にkeyWebPage.curentState.navigateTo
(まだnullである) が呼び出されるためと思われます。
tabController.index = tabIndex;
keyWebPage.currentState.navigateTo(url); //executed 'before' the new TabView initialization
この問題の原因を疑っていますが、解決方法がわかりませんでした。
main.dart
final GlobalKey<PageWebState> keyWebPage = GlobalKey();
class _MyHomePageState extends State<MyHomePage> {
final CupertinoTabController tabController = CupertinoTabController();
int _currentTabIndex = 0;
WebPage pageWeb;
@override
void initState() {
super.initState();
pageWeb = new PageWeb(
this,
key: keyWebPage,
);
}
void navigateTab(int tabIndex, String url) {
setState(() {
_currentTabIndex = tabIndex;
tabController.index = tabIndex;
// HERE is the error occurring part
keyWebPage.currentState.navigateTo(url);
});
}
@override
Widget build(BuildContext context) {
final Widget scaffold = CupertinoTabScaffold(
controller: tabController,
tabBar: CupertinoTabBar(
currentIndex: _currentTabIndex,
onTap: (index) {
setState(() {
_currentTabIndex = index;
});
},
items: const <BottomNavigationBarItem>[
const BottomNavigationBarItem(icon: const Icon(Icons.home), title: Text('Start')),
const BottomNavigationBarItem(icon: const Icon(Icons.web), title: Text('Webpage')),
],
),
tabBuilder: (context, index) {
CupertinoTabView _viewWidget;
switch (index) {
case 0:
_viewWidget = CupertinoTabView(
builder: (context) {
return Center(
child: CupertinoButton(
child: Text('Navigate'),
onPressed: () {
navigateTab(1, 'https://stackoverflow.com/');
},
),
);
},
);
break;
case 1:
_viewWidget = CupertinoTabView(
builder: (context) {
return pageWeb;
},
);
break;
}
return _viewWidget;
},
);
return scaffold;
}
}
WebPage.dart
final Completer<WebViewController> _controller = Completer<WebViewController>();
class PageWeb extends StatefulWidget {
final delegate;
final ObjectKey key;
PageWeb(this.delegate, this.key);
@override
PageWebState createState() {
return PageWebState();
}
}
void navigateTo(String url) { //Function that will be called on main.dart
controller.future.then((controller) => controller.loadUrl(url));
}
class PageWebState extends State<PageWeb> {
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text("Test"),
),
child: SafeArea(
child: Container(
child: new WebView(
key: widget.key,
initialUrl: "https://www.google.com/",
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
))));
}
}
URLが変更され、ボタンが複数回クリックされる可能性があるため、変数を渡すためにコンストラクターを使用することは考慮されていないことに注意してください。