Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[webview_flutter] WIP Webview transparent background #4165

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Color;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Handler;
Expand Down Expand Up @@ -435,6 +436,10 @@ private void applySettings(Map<String, Object> settings) {
case "allowsInlineMediaPlayback":
// no-op inline media playback is always allowed on Android.
break;
case "opaque":
boolean opaque = (boolean) settings.get(key);
webView.setBackgroundColor(opaque ? Color.WHITE : Color.TRANSPARENT);
break;
default:
throw new IllegalArgumentException("Unknown WebView setting: " + key);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const String kNavigationExamplePage = '''
<head><title>Navigation Delegate Example</title></head>
<body>
<p>
The navigation delegate is set to block navigation to the youtube website.
The navigation delegate is set to block navigation to the youtube website, and as the webview background is transparent, you can see scaffold background.
</p>
<ul>
<ul><a href="https://www.youtube.com/">https://www.youtube.com/</a></ul>
Expand Down Expand Up @@ -45,6 +45,7 @@ class _WebViewExampleState extends State<WebViewExample> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green,
appBar: AppBar(
title: const Text('Flutter WebView example'),
// This drop down menu demonstrates that Flutter widgets can be shown over the web view.
Expand Down Expand Up @@ -83,6 +84,7 @@ class _WebViewExampleState extends State<WebViewExample> {
print('Page finished loading: $url');
},
gestureNavigationEnabled: true,
opaque: false,
);
}),
floatingActionButton: favoriteButton(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,11 @@ - (NSString*)applySettings:(NSDictionary<NSString*, id>*)settings {
} else if ([key isEqualToString:@"userAgent"]) {
NSString* userAgent = settings[key];
[self updateUserAgent:[userAgent isEqual:[NSNull null]] ? nil : userAgent];
} else if ([key isEqualToString:@"opaque"]) {
bool opaque = [settings[@"opaque"] boolValue];
_webView.opaque = opaque;
_webView.backgroundColor = opaque ? UIColor.whiteColor : UIColor.clearColor;
_webView.scrollView.backgroundColor = opaque ? UIColor.whiteColor : UIColor.clearColor;
} else {
[unknownKeys addObject:key];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ class WebSettings {
this.gestureNavigationEnabled,
this.allowsInlineMediaPlayback,
required this.userAgent,
this.opaque,
}) : assert(userAgent != null);

/// The JavaScript execution mode to be used by the webview.
Expand Down Expand Up @@ -434,6 +435,9 @@ class WebSettings {
/// See also: [WebView.gestureNavigationEnabled]
final bool? gestureNavigationEnabled;

/// If set to `false`, the webview background will be transparent.
final bool? opaque;

@override
String toString() {
return 'WebSettings(javascriptMode: $javascriptMode, hasNavigationDelegate: $hasNavigationDelegate, hasProgressTracking: $hasProgressTracking, debuggingEnabled: $debuggingEnabled, gestureNavigationEnabled: $gestureNavigationEnabled, userAgent: $userAgent, allowsInlineMediaPlayback: $allowsInlineMediaPlayback)';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController {
_addIfNonNull(
'allowsInlineMediaPlayback', settings.allowsInlineMediaPlayback);
_addSettingIfPresent('userAgent', settings.userAgent);
_addIfNonNull('opaque', settings.opaque);
return map;
}

Expand Down
10 changes: 10 additions & 0 deletions packages/webview_flutter/webview_flutter/lib/webview_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ class WebView extends StatefulWidget {
this.initialMediaPlaybackPolicy =
AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
this.allowsInlineMediaPlayback = false,
this.opaque = true,
}) : assert(javascriptMode != null),
assert(initialMediaPlaybackPolicy != null),
assert(allowsInlineMediaPlayback != null),
Expand Down Expand Up @@ -415,6 +416,9 @@ class WebView extends StatefulWidget {
/// The default policy is [AutoMediaPlaybackPolicy.require_user_action_for_all_media_types].
final AutoMediaPlaybackPolicy initialMediaPlaybackPolicy;

/// If set to `false`, the webview background will be transparent.
final bool opaque;

@override
State<StatefulWidget> createState() => _WebViewState();
}
Expand Down Expand Up @@ -491,6 +495,7 @@ WebSettings _webSettingsFromWidget(WebView widget) {
gestureNavigationEnabled: widget.gestureNavigationEnabled,
allowsInlineMediaPlayback: widget.allowsInlineMediaPlayback,
userAgent: WebSetting<String?>.of(widget.userAgent),
opaque: widget.opaque,
);
}

Expand All @@ -512,6 +517,7 @@ WebSettings _clearUnchangedWebSettings(
bool? hasProgressTracking;
bool? debuggingEnabled;
WebSetting<String?> userAgent = WebSetting.absent();
bool? opaque;
if (currentValue.javascriptMode != newValue.javascriptMode) {
javascriptMode = newValue.javascriptMode;
}
Expand All @@ -527,13 +533,17 @@ WebSettings _clearUnchangedWebSettings(
if (currentValue.userAgent != newValue.userAgent) {
userAgent = newValue.userAgent;
}
if (currentValue.opaque != newValue.opaque) {
opaque = newValue.opaque;
}

return WebSettings(
javascriptMode: javascriptMode,
hasNavigationDelegate: hasNavigationDelegate,
hasProgressTracking: hasProgressTracking,
debuggingEnabled: debuggingEnabled,
userAgent: userAgent,
opaque: opaque,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,27 @@ void main() {
expect(platformWebView.javascriptMode, JavascriptMode.disabled);
});

testWidgets('opaque', (WidgetTester tester) async {
await tester.pumpWidget(
const WebView(
initialUrl: 'https://youtube.com',
opaque: false,
),
);

final FakePlatformWebView platformWebView =
fakePlatformViewsController.lastCreatedView!;
expect(platformWebView.opaque, false);

await tester.pumpWidget(
const WebView(
initialUrl: 'https://youtube.com',
opaque: true,
),
);
expect(platformWebView.opaque, true);
});

testWidgets('Load url', (WidgetTester tester) async {
WebViewController? controller;
await tester.pumpWidget(
Expand Down Expand Up @@ -940,6 +961,7 @@ class FakePlatformWebView {
params['settings']['hasNavigationDelegate'] ?? false;
debuggingEnabled = params['settings']['debuggingEnabled'];
userAgent = params['settings']['userAgent'];
opaque = params['settings']['opaque'];
channel = MethodChannel(
'plugins.flutter.io/webview_$id', const StandardMethodCodec());
channel.setMockMethodCallHandler(onMethodCall);
Expand All @@ -959,6 +981,7 @@ class FakePlatformWebView {
bool? hasNavigationDelegate;
bool? debuggingEnabled;
String? userAgent;
bool? opaque;

Future<dynamic> onMethodCall(MethodCall call) {
switch (call.method) {
Expand All @@ -976,6 +999,9 @@ class FakePlatformWebView {
if (call.arguments['debuggingEnabled'] != null) {
debuggingEnabled = call.arguments['debuggingEnabled'];
}
if (call.arguments['opaque'] != null) {
opaque = call.arguments['opaque'];
}
userAgent = call.arguments['userAgent'];
break;
case 'canGoBack':
Expand Down