Issue
My goal is to make a WebView
app with several CupertinoTabViews
that when clicking each BottomNavigationBarItem
, CupertinoTabScaffold
shows different WebView
containing widgets; pageA
and pageB
.
As the application launches, the first WebView successfully shows the initial URL webpage.
However, when clicking another Tab button (trying to show another WebView), Unhandled Exception: Bad state: Future already completed is thrown.
main.dart
class _MyHomePageState extends State<MyHomePage> {
int _currentTabIndex = 0;
PageWeb pageA;
PageWeb pageB;
@override
void initState() {
super.initState();
pageA = new PageWeb(this, ObjectKey(0), "A");
pageB = new PageWeb(this, ObjectKey(1), "B");
}
@override
Widget build(BuildContext context) {
final Widget scaffold = CupertinoTabScaffold(
tabBar: CupertinoTabBar(
currentIndex: _currentTabIndex,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home), title: Text('A')),
BottomNavigationBarItem(
icon: Icon(Icons.photo), title: Text('B')),
],
),
tabBuilder: (context, index) {
CupertinoTabView returnValue;
switch (index) {
case 0:
returnValue = CupertinoTabView(
builder: (context) {
return pageA;
},
);
break;
case 1:
returnValue = CupertinoTabView(
builder: (context) {
return pageB;
},
);
break;
}
return returnValue;
},
);
return scaffold;
}
}
pageweb.dart (PageWeb class)
final Completer<WebViewController> _controller = Completer<WebViewController>();
class PageWeb extends StatefulWidget {
final delegate;
final ObjectKey key;
final String navTitle;
PageWeb(this.delegate, this.key, this.navTitle);
@override
_PageWebState createState() {
return _PageWebState();
}
}
class _PageWebState extends State<PageWeb> {
bool _isLoading = true;
final cookieManager = WebviewCookieManager();
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text(widget.navTitle),
),
child: SafeArea(
child: Container(
child: new WebView(
key: widget.key,
initialUrl: "https://www.google.com/search?q=${widget.navTitle}",
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
// Here is the error occurring part.
},
onPageStarted: (String pageUrl) {
setState(() {
_isLoading = true;
});
},
onPageFinished: (String pageUrl) {
setState(() {
_isLoading = false;
});
},
))));
}
}
The Unhandled Exception: Bad state: Future already completed error locates the following line:
_controller.complete(webViewController);
Solution
The solution was simple. Move the _controller
declaration inside the class.
Answered By – klados
Answer Checked By – Clifford M. (FlutterFixes Volunteer)