flutter_webview 不垂直滚动(overflow-y 滚动条不显示)
flutter_webview not scrolling vertically (overflow-y scrollbar not showing)
我正在尝试在 Flutter 应用程序中嵌入一个特定的网页 (https://bandcamp.com/EmbeddedPlayer/album=3538525485/size=large/bgcol=ffffff/linkcol=9c7b14/transparent=true/),但由于内容溢出,该页面无法滚动。
以下是它的显示方式,请注意可滚动的播放列表(来自 macOS Safari 响应式设计模式的屏幕截图)。
但在Flutter WebView中,目前显示如下(iOS模拟器截图):
注意,虽然有内容溢出,但是没有滚动条,无法滚动。
代码如下:
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const CupertinoApp(
theme: CupertinoThemeData(
brightness: Brightness.light,
),
home: Home(),
);
}
}
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: Text('Home'),
),
child: SafeArea(
child: WebView(
initialUrl: 'https://bandcamp.com/EmbeddedPlayer/album=3538525485/size=large/bgcol=ffffff/linkcol=9c7b14/transparent=true/',
javascriptMode: JavascriptMode.unrestricted,
zoomEnabled: false,
gestureRecognizers: {}..add(Factory(() => VerticalDragGestureRecognizer())),
),
),
);
}
}
非常感谢任何帮助。
事实证明,我必须将 Bandcamp 播放器嵌入到 iframe 中。
在对嵌入式播放器的响应式布局应用一些基于 LayoutBuilder
约束的 CSS 之后,现在一切都按预期工作。
这是最终代码:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const CupertinoApp(
theme: CupertinoThemeData(
brightness: Brightness.light,
),
home: Home(),
);
}
}
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _visibleChildIndex = 0;
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: Text(
'WebView Page',
overflow: TextOverflow.ellipsis,
),
),
child: SafeArea(
child: IndexedStack(
index: _visibleChildIndex,
children: [
const Center(
child: CircularProgressIndicator.adaptive(),
),
Center(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Icon(
Icons.warning_amber_rounded,
size: 64.0,
),
SizedBox(height: 8.0),
Text(
'Failed to load page.',
textAlign: TextAlign.center,
),
],
),
),
_buildWebView(
'https://bandcamp.com/EmbeddedPlayer/album=3538525485/size=large/bgcol=ffffff/linkcol=9c7b14/transparent=true/'),
],
),
),
);
}
String _getBandCampPlayerHTML({
required String iframeSrc,
required double width,
required double height,
}) {
return '''
<!DOCTYPE html>
<html>
<head>
<title>Music Album</title>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<style>
html, body {
margin: 0;
padding: 0;
overflow: hidden;
}
.page-container {
max-width: ${width}px;
margin: 0 auto;
}
.iframe-container {
width: 0;
height: 0;
position: relative;
padding: ${height}px 0 0 ${width}px;
}
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
}
</style>
</head>
<body>
<div class="page-container">
<div class="iframe-container">
<iframe src="$iframeSrc" scrolling="no" allow="encrypted-media;"></iframe>
</div>
</div>
</body>
</html>
''';
}
Widget _buildWebView(String src) {
return LayoutBuilder(builder: (context, constraints) {
double width = 700.0;
final height = constraints.maxHeight;
width = (constraints.maxWidth > width) ? width : constraints.maxWidth;
if (height <= width) {
width = height * 0.6;
}
return WebView(
initialUrl: Uri.dataFromString(
_getBandCampPlayerHTML(
iframeSrc: src,
width: width,
height: height,
),
mimeType: 'text/html',
).toString(),
javascriptMode: JavascriptMode.unrestricted,
allowsInlineMediaPlayback: true,
onWebResourceError: (error) {
setState(() {
_visibleChildIndex = 1;
});
},
onPageFinished: (url) {
setState(() {
_visibleChildIndex = 2;
});
},
);
});
}
}
我正在尝试在 Flutter 应用程序中嵌入一个特定的网页 (https://bandcamp.com/EmbeddedPlayer/album=3538525485/size=large/bgcol=ffffff/linkcol=9c7b14/transparent=true/),但由于内容溢出,该页面无法滚动。
以下是它的显示方式,请注意可滚动的播放列表(来自 macOS Safari 响应式设计模式的屏幕截图)。
但在Flutter WebView中,目前显示如下(iOS模拟器截图):
注意,虽然有内容溢出,但是没有滚动条,无法滚动。
代码如下:
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const CupertinoApp(
theme: CupertinoThemeData(
brightness: Brightness.light,
),
home: Home(),
);
}
}
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: Text('Home'),
),
child: SafeArea(
child: WebView(
initialUrl: 'https://bandcamp.com/EmbeddedPlayer/album=3538525485/size=large/bgcol=ffffff/linkcol=9c7b14/transparent=true/',
javascriptMode: JavascriptMode.unrestricted,
zoomEnabled: false,
gestureRecognizers: {}..add(Factory(() => VerticalDragGestureRecognizer())),
),
),
);
}
}
非常感谢任何帮助。
事实证明,我必须将 Bandcamp 播放器嵌入到 iframe 中。
在对嵌入式播放器的响应式布局应用一些基于 LayoutBuilder
约束的 CSS 之后,现在一切都按预期工作。
这是最终代码:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const CupertinoApp(
theme: CupertinoThemeData(
brightness: Brightness.light,
),
home: Home(),
);
}
}
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _visibleChildIndex = 0;
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: Text(
'WebView Page',
overflow: TextOverflow.ellipsis,
),
),
child: SafeArea(
child: IndexedStack(
index: _visibleChildIndex,
children: [
const Center(
child: CircularProgressIndicator.adaptive(),
),
Center(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Icon(
Icons.warning_amber_rounded,
size: 64.0,
),
SizedBox(height: 8.0),
Text(
'Failed to load page.',
textAlign: TextAlign.center,
),
],
),
),
_buildWebView(
'https://bandcamp.com/EmbeddedPlayer/album=3538525485/size=large/bgcol=ffffff/linkcol=9c7b14/transparent=true/'),
],
),
),
);
}
String _getBandCampPlayerHTML({
required String iframeSrc,
required double width,
required double height,
}) {
return '''
<!DOCTYPE html>
<html>
<head>
<title>Music Album</title>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<style>
html, body {
margin: 0;
padding: 0;
overflow: hidden;
}
.page-container {
max-width: ${width}px;
margin: 0 auto;
}
.iframe-container {
width: 0;
height: 0;
position: relative;
padding: ${height}px 0 0 ${width}px;
}
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
}
</style>
</head>
<body>
<div class="page-container">
<div class="iframe-container">
<iframe src="$iframeSrc" scrolling="no" allow="encrypted-media;"></iframe>
</div>
</div>
</body>
</html>
''';
}
Widget _buildWebView(String src) {
return LayoutBuilder(builder: (context, constraints) {
double width = 700.0;
final height = constraints.maxHeight;
width = (constraints.maxWidth > width) ? width : constraints.maxWidth;
if (height <= width) {
width = height * 0.6;
}
return WebView(
initialUrl: Uri.dataFromString(
_getBandCampPlayerHTML(
iframeSrc: src,
width: width,
height: height,
),
mimeType: 'text/html',
).toString(),
javascriptMode: JavascriptMode.unrestricted,
allowsInlineMediaPlayback: true,
onWebResourceError: (error) {
setState(() {
_visibleChildIndex = 1;
});
},
onPageFinished: (url) {
setState(() {
_visibleChildIndex = 2;
});
},
);
});
}
}