如何在 Flutter 的 tabbarwiew 中使 webview 可滚动
Posted
技术标签:
【中文标题】如何在 Flutter 的 tabbarwiew 中使 webview 可滚动【英文标题】:How to make a webview scrollable in tabbarwiew in Flutter 【发布时间】:2020-05-31 06:49:48 【问题描述】:我花了将近两天的时间试图弄清楚如何在 Flutter 的 tabbarview 中使 webview 可滚动。我知道 TabBarWiew 小部件应该包装在一个固定高度的小部件中,有什么办法可以解决这个问题? 我不知道它是否有帮助,但我的 minSdkVersion 是 16,targetSdkVersion 是 28, 这是 flutter --version 命令的输出
Flutter 1.12.13+hotfix.5 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 27321ebbad (10 weeks ago) • 2019-12-10 18:15:01 -0800
Engine • revision 2994f7e1e6
Tools • Dart 2.7.0
下面是我正在构建的页面的代码。
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget
// This widget is the root of your application.
@override
Widget build(BuildContext context)
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Pays'),
);
class MyHomePage extends StatefulWidget
MyHomePage(Key key, this.title) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin
@override
Widget build(BuildContext context)
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
double screenHeight = MediaQuery.of(context).size.height;
final List<Tab> myTabs = <Tab>[
Tab(text: 'LEFT'),
Tab(text: 'RIGHT'),
];
TabController _tabController;
@override
void initState()
super.initState();
_tabController = TabController(vsync: this, length: myTabs.length);
@override
void dispose()
_tabController.dispose();
super.dispose();
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
backgroundColor: Colors.red[800],
),
body: Container(
color: Colors.grey[100],
child: ListView(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Image.network(
'https://lh3.googleusercontent.com/proxy/dThF-49TD0synkY_v1F0mh2HQFp_P5bxYvdLI1msK-aD7h4CtzctJpJP3Cm89LyAWAg21xqvUDdQjdRi2yDH4iEU1wr_LT3BO8iOmx141QOtzXPgUpXW7ulAlHUtAJ4Z0yea_Qr4sWZfApns3VuAbxNcTNISWdStSoJEZ9-OmRypu-3YTQ',
height: 150,
fit: BoxFit.fitWidth,
alignment: Alignment.topCenter,
filterQuality: FilterQuality.high,
)),
],
),
SizedBox(
height: 1,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('237',
style: TextStyle(
color: Colors.black,
fontSize: 35,
fontWeight: FontWeight.bold)),
SizedBox(
width: 5,
),
Image.network(
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQJrM_W9cpz33KFyqL_L-meeCuH_Kyufoohxjlh06XdBnIbel0j&s',
height: 30,
),
Spacer(),
Image.network(
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTwnqIeW1RJHtAhRE7ccZ-4s4ymEh5zHRYAdidO7p9GfDnOwziY&s',
height: 50,
)
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
'Cameroun',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontSize: 25,
fontWeight: FontWeight.bold),
)
]),
),
SizedBox(height: 5),
NestedTabBar()
],
)),
// This trailing comma makes auto-formatting nicer for build methods.
);
class NestedTabBar extends StatefulWidget
@override
_NestedTabBarState createState() => _NestedTabBarState();
class _NestedTabBarState extends State<NestedTabBar>
with TickerProviderStateMixin
TabController _nestedTabController;
ScrollController _scrollController;
@override
void initState()
//_scrollController = ScrollController();
super.initState();
_nestedTabController = new TabController(length: 2, vsync: this);
//_nestedTabController.addListener(_handleTabSelection);
@override
void dispose()
_nestedTabController.dispose();
super.dispose();
@override
Widget build(BuildContext context)
double screenHeight = MediaQuery.of(context).size.height;
return Column(
children: <Widget>[
TabBar(
controller: _nestedTabController,
indicatorColor: Colors.teal,
labelColor: Colors.teal,
unselectedLabelColor: Colors.black54,
isScrollable: true,
tabs: <Widget>[
Tab(
text: "A propos & Statistiques",
),
Tab(
text: "Wiki",
)
],
),
Container(
height: screenHeight * 0.9,
margin: EdgeInsets.only(left: 8.0, right: 8.0),
child: TabBarView(
controller: _nestedTabController,
children: <Widget>[
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
),
child: Text('Simple text')),
/*GestureDetector(
child: MyWebView(selectedUrl: 'https://fr.wikipedia.org/wiki/Lewis_Hamilton'),
),*/
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
),
child: MyWebView(
selectedUrl: 'https://fr.wikipedia.org/wiki/Cameroun'),
),
],
),
),
// MyWebView(selectedUrl: 'https://fr.wikipedia.org/wiki/Lewis_Hamilton')
],
);
class MyWebView extends StatefulWidget
final String selectedUrl;
MyWebView(
@required this.selectedUrl,
);
@override
_MyWebViewState createState() => _MyWebViewState();
class _MyWebViewState extends State<MyWebView>
Completer<WebViewController> _controller;
@override
void initState()
super.initState();
_controller = Completer<WebViewController>();
@override
void dispose()
super.dispose();
_controller = null;
@override
Widget build(BuildContext context)
return Scaffold(
body: WebView(
initialUrl: widget.selectedUrl,
gestureRecognizers: Set()
..add(Factory<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer())),
gestureNavigationEnabled: true,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController)
_controller.complete(webViewController);
,
));
【问题讨论】:
【参考方案1】:您可以在下面复制粘贴运行完整代码
你可以使用包https://pub.dev/packages/flutter_inappwebview
第 1 步:将 android minSdkVersion
更改为 17
第2步:参考包与以下,因为这个问题。 https://github.com/pichillilorenzo/flutter_inappwebview/issues/220
flutter_inappwebview:
git:
url: https://github.com/pichillilorenzo/flutter_inappwebview.git
ref: master
第三步:编码sn-p
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
),
child: InAppWebView(
initialUrl: "https://fr.wikipedia.org/wiki/Lewis_Hamilton",
initialHeaders: ,
工作演示
完整代码
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget
// This widget is the root of your application.
@override
Widget build(BuildContext context)
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Pays'),
);
class MyHomePage extends StatefulWidget
MyHomePage(Key key, this.title) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin
@override
Widget build(BuildContext context)
double screenHeight = MediaQuery.of(context).size.height;
final List<Tab> myTabs = <Tab>[
Tab(text: 'LEFT'),
Tab(text: 'RIGHT'),
];
TabController _tabController;
@override
void initState()
super.initState();
_tabController = TabController(vsync: this, length: myTabs.length);
@override
void dispose()
_tabController.dispose();
super.dispose();
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
backgroundColor: Colors.red[800],
),
body: Container(
color: Colors.grey[100],
child: ListView(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Image.network(
'https://lh3.googleusercontent.com/proxy/dThF-49TD0synkY_v1F0mh2HQFp_P5bxYvdLI1msK-aD7h4CtzctJpJP3Cm89LyAWAg21xqvUDdQjdRi2yDH4iEU1wr_LT3BO8iOmx141QOtzXPgUpXW7ulAlHUtAJ4Z0yea_Qr4sWZfApns3VuAbxNcTNISWdStSoJEZ9-OmRypu-3YTQ',
height: 150,
fit: BoxFit.fitWidth,
alignment: Alignment.topCenter,
filterQuality: FilterQuality.high,
)),
],
),
SizedBox(
height: 1,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('237',
style: TextStyle(
color: Colors.black,
fontSize: 35,
fontWeight: FontWeight.bold)),
SizedBox(
width: 5,
),
Image.network(
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQJrM_W9cpz33KFyqL_L-meeCuH_Kyufoohxjlh06XdBnIbel0j&s',
height: 30,
),
Spacer(),
Image.network(
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTwnqIeW1RJHtAhRE7ccZ-4s4ymEh5zHRYAdidO7p9GfDnOwziY&s',
height: 50,
)
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
'Cameroun',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontSize: 25,
fontWeight: FontWeight.bold),
)
]),
),
SizedBox(height: 5),
NestedTabBar()
],
)),
// This trailing comma makes auto-formatting nicer for build methods.
);
class NestedTabBar extends StatefulWidget
@override
_NestedTabBarState createState() => _NestedTabBarState();
class _NestedTabBarState extends State<NestedTabBar>
with TickerProviderStateMixin
TabController _nestedTabController;
ScrollController _scrollController;
InAppWebViewController webView;
String url = "";
double progress = 0;
@override
void initState()
//_scrollController = ScrollController();
super.initState();
_nestedTabController = new TabController(length: 2, vsync: this);
//_nestedTabController.addListener(_handleTabSelection);
@override
void dispose()
_nestedTabController.dispose();
super.dispose();
@override
Widget build(BuildContext context)
double screenHeight = MediaQuery.of(context).size.height;
return Column(
children: <Widget>[
TabBar(
controller: _nestedTabController,
indicatorColor: Colors.teal,
labelColor: Colors.teal,
unselectedLabelColor: Colors.black54,
isScrollable: true,
tabs: <Widget>[
Tab(
text: "A propos & Statistiques",
),
Tab(
text: "Wiki",
)
],
),
Container(
height: screenHeight * 0.9,
margin: EdgeInsets.only(left: 8.0, right: 8.0),
child: TabBarView(
controller: _nestedTabController,
children: <Widget>[
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
),
child: Text('Simple text')),
/*GestureDetector(
child: MyWebView(selectedUrl: 'https://fr.wikipedia.org/wiki/Lewis_Hamilton'),
),*/
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
),
child: InAppWebView(
initialUrl: "https://fr.wikipedia.org/wiki/Lewis_Hamilton",
initialHeaders: ,
initialOptions: InAppWebViewWidgetOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
)
),
onWebViewCreated: (InAppWebViewController controller)
webView = controller;
,
onLoadStart: (InAppWebViewController controller, String url)
setState(()
this.url = url;
);
,
onLoadStop: (InAppWebViewController controller, String url) async
setState(()
this.url = url;
);
,
onProgressChanged: (InAppWebViewController controller, int progress)
setState(()
this.progress = progress / 100;
);
,
),
),
],
),
),
// MyWebView(selectedUrl: 'https://fr.wikipedia.org/wiki/Lewis_Hamilton')
],
);
【讨论】:
以上是关于如何在 Flutter 的 tabbarwiew 中使 webview 可滚动的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法在 Flutter 的 TabBar 中创建下拉列表?
Flutter - 如何在不每次下载flutter和dart sdk的情况下切换flutter频道
Flutter-如何在flutter的整个应用程序生命周期中将数据保存在内存中?
Flutter - 如何在 Flutter 应用上实现 News Count