BottomNavigatonBar 的 onTap(index) 方法上的 SetState() 不会重建小部件树
SetState() on BottomNavigatonBar's onTap(index) method does not rebuild widget tree
我正在尝试将 webview_flutter
WebView
连接到 BottomNavigationBar
。
我希望在点击选项卡时使用新的 URL 重新加载视图。在
onTap
回调我将 _currentUrl
更新为新的 url 并使用新的选项卡索引调用设置状态。
为什么标签栏正在更新,但网页视图没有重建?
我错过了什么?
class WebViewApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return WebViewState();
}
}
class WebViewState extends State<WebViewApp> {
int _currentTabIndex = 0;
String _currentUrl = URL.home;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter WebView Demo',
home: Scaffold(
body: WebView(initialUrl: _currentUrl),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentTabIndex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
title: Text('Search'),
),
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today),
title: Text('Profile'),
),
],
onTap: (index) {
switch (index) {
case 0:
_currentUrl = URL.home;
break;
case 1:
_currentUrl = URL.search;
break;
case 2:
_currentUrl = URL.calendar;
break;
}
setState(() {
_currentTabIndex = index;
});
},
),
),
);
}
}
您可以使用 WebView 的 WebViewController 来更改 url 的 webview
将以下代码添加到您的 WebView 小部件:
body: WebView(
initialUrl: _currentUrl,
onWebViewCreated: (WebViewController webController) {
_webController = webController;
},
),
现在,在您将 WebViewController 分配给您的 WebViewController 实例后,您可以使用 WebViewController
的 loadUrl() 方法更改当前 webview 的 url
因此您可以将 onTap 处理程序的代码更改为以下内容:
onTap: (index) {
switch (index) {
case 0:
_webController.loadUrl('your_home_url');
break;
case 1:
_webController.loadUrl('your_search_url');
break;
case 2:
_webController.loadUrl('your_calander_url');
break;
}
},
WebViews 和 setState 的问题是整个 Widget / Page 将被重建,包括 WebView 的实例,但您只想更改当前 WebView 会话中的 url...
感谢乔尔的评论
是的,发布一个跨平台框架很奇怪,基本组件只能在一个平台上工作,但是是的,希望他们能在 10 月之前修复它,因为他们 github...
我检查了我的 post,WebView 应该加载新的 url。我忘记的是在导航的 onTap
处理程序中更新 _currentTabIndex
。
但无论如何:我为你的案例做了一个简单的例子。对我来说很好用...
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'WebView App',
debugShowCheckedModeBanner: false,
home: WebPage(),
);
}
}
class WebPage extends StatefulWidget {
int currentTabIndex = 0;
@override
_WebPageState createState() => _WebPageState();
}
class _WebPageState extends State<WebPage> {
List<String> _urls = [
'https://www.zdf.de/nachrichten/heute/rubrik-politik-100.html',
'https://www.zdf.de/nachrichten/heute/rubrik-wirtschaft-100.html',
'https://www.zdf.de/nachrichten/heute/rubrik-panorama-100.html'
];
WebViewController _webController;
@override
Widget build(BuildContext context) {
print('<----- build init ----->');
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('WebView'),
),
body: WebView(
initialUrl: _urls[widget.currentTabIndex],
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webController) {
_webController = webController;
},
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: widget.currentTabIndex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.people),
title: Text('Politik')
),
BottomNavigationBarItem(
icon: Icon(Icons.public),
title: Text('Wirtschaft')
),
BottomNavigationBarItem(
icon: Icon(Icons.pie_chart_outlined),
title: Text('Panorama')
)
],
onTap: (selectedIndex) {
_webController.loadUrl(_urls[selectedIndex]);
setState(() {
widget.currentTabIndex = selectedIndex;
});
},
),
);
}
}
请注意,我在重建页面的 onTap
处理程序末尾调用了 setState()
,但奇怪的是 WebView 不会重新初始化!?我认为一定是这样,但是 flutter 必须以某种方式处理这个问题......
另请注意,我将您的 _currentTabIndex
变量从您的 WebViewState
class 移至其上层父项 class WebViewApp
。问题是,如果您通过 setState()
重建页面,_currentTabIndex
将始终重新初始化为 0。为了教程的缘故,我只是将它向上移动,但也许您可以将它用作全局参数。 .
但是,是的,WebView 仍然有点令人困惑,它在 iOS 和 Android WebView 套件之间有很多差异(在一天结束时,flutter WebView 是 "only" 当前原生 WebView 套件的包装器)
希望对您有所帮助,祝您好运!
我正在尝试将 webview_flutter
WebView
连接到 BottomNavigationBar
。
我希望在点击选项卡时使用新的 URL 重新加载视图。在
onTap
回调我将 _currentUrl
更新为新的 url 并使用新的选项卡索引调用设置状态。
为什么标签栏正在更新,但网页视图没有重建? 我错过了什么?
class WebViewApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return WebViewState();
}
}
class WebViewState extends State<WebViewApp> {
int _currentTabIndex = 0;
String _currentUrl = URL.home;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter WebView Demo',
home: Scaffold(
body: WebView(initialUrl: _currentUrl),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentTabIndex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
title: Text('Search'),
),
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today),
title: Text('Profile'),
),
],
onTap: (index) {
switch (index) {
case 0:
_currentUrl = URL.home;
break;
case 1:
_currentUrl = URL.search;
break;
case 2:
_currentUrl = URL.calendar;
break;
}
setState(() {
_currentTabIndex = index;
});
},
),
),
);
}
}
您可以使用 WebView 的 WebViewController 来更改 url 的 webview
将以下代码添加到您的 WebView 小部件:
body: WebView(
initialUrl: _currentUrl,
onWebViewCreated: (WebViewController webController) {
_webController = webController;
},
),
现在,在您将 WebViewController 分配给您的 WebViewController 实例后,您可以使用 WebViewController
的 loadUrl() 方法更改当前 webview 的 url因此您可以将 onTap 处理程序的代码更改为以下内容:
onTap: (index) {
switch (index) {
case 0:
_webController.loadUrl('your_home_url');
break;
case 1:
_webController.loadUrl('your_search_url');
break;
case 2:
_webController.loadUrl('your_calander_url');
break;
}
},
WebViews 和 setState 的问题是整个 Widget / Page 将被重建,包括 WebView 的实例,但您只想更改当前 WebView 会话中的 url...
感谢乔尔的评论
是的,发布一个跨平台框架很奇怪,基本组件只能在一个平台上工作,但是是的,希望他们能在 10 月之前修复它,因为他们 github...
我检查了我的 post,WebView 应该加载新的 url。我忘记的是在导航的 onTap
处理程序中更新 _currentTabIndex
。
但无论如何:我为你的案例做了一个简单的例子。对我来说很好用...
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'WebView App',
debugShowCheckedModeBanner: false,
home: WebPage(),
);
}
}
class WebPage extends StatefulWidget {
int currentTabIndex = 0;
@override
_WebPageState createState() => _WebPageState();
}
class _WebPageState extends State<WebPage> {
List<String> _urls = [
'https://www.zdf.de/nachrichten/heute/rubrik-politik-100.html',
'https://www.zdf.de/nachrichten/heute/rubrik-wirtschaft-100.html',
'https://www.zdf.de/nachrichten/heute/rubrik-panorama-100.html'
];
WebViewController _webController;
@override
Widget build(BuildContext context) {
print('<----- build init ----->');
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('WebView'),
),
body: WebView(
initialUrl: _urls[widget.currentTabIndex],
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webController) {
_webController = webController;
},
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: widget.currentTabIndex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.people),
title: Text('Politik')
),
BottomNavigationBarItem(
icon: Icon(Icons.public),
title: Text('Wirtschaft')
),
BottomNavigationBarItem(
icon: Icon(Icons.pie_chart_outlined),
title: Text('Panorama')
)
],
onTap: (selectedIndex) {
_webController.loadUrl(_urls[selectedIndex]);
setState(() {
widget.currentTabIndex = selectedIndex;
});
},
),
);
}
}
请注意,我在重建页面的 onTap
处理程序末尾调用了 setState()
,但奇怪的是 WebView 不会重新初始化!?我认为一定是这样,但是 flutter 必须以某种方式处理这个问题......
另请注意,我将您的 _currentTabIndex
变量从您的 WebViewState
class 移至其上层父项 class WebViewApp
。问题是,如果您通过 setState()
重建页面,_currentTabIndex
将始终重新初始化为 0。为了教程的缘故,我只是将它向上移动,但也许您可以将它用作全局参数。 .
但是,是的,WebView 仍然有点令人困惑,它在 iOS 和 Android WebView 套件之间有很多差异(在一天结束时,flutter WebView 是 "only" 当前原生 WebView 套件的包装器)
希望对您有所帮助,祝您好运!