WKWebView 在安全区域的横向内容宽度不正确
WKWebView incorrect content width in landscape with safe area
这是它的样子:
最简单的重现代码:
#import "ViewController.h"
#import <WebKit/WebKit.h>
@implementation ViewController
- (void)loadView
{
WKWebView* webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:[[WKWebViewConfiguration alloc] init]];
self.view = webView;
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://apple.com"]]];
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
@end
这只会发生在设置了 viewport-fit=cover
的网站上。如果你在 Safari 中打开相同的网站,你可以看到第一个绘制框架有同样的问题,但它立即正确调整大小。
只有在横向启动时才会发生这种情况。
旋转到纵向并返回到横向解决了这个问题。即使最小化应用程序并再次打开它也能解决这个问题。
那么我可以通过代码做些什么来强制它自行修复吗?
我已经尝试调用 setNeedsLayout
和 layoutIfNeeded
到整个 WKWebView
树。设置 scroller insets 将使内容看起来像没有设置 viewport-fit=cover
。
这发生在 iOS 12 和 13(已测试)和 iOS 13 模拟器上。
您好,您需要更改视口。
请使用以下代码更改您的 "loadView" 函数。
- (void)loadView
{
NSString *jScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
WKUserContentController *wkUController = [[WKUserContentController alloc] init];
[wkUController addUserScript:wkUScript];
WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
wkWebConfig.userContentController = wkUController;
WKWebView* webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:wkWebConfig];
webView.insetsLayoutMarginsFromSafeArea = false;
webView.scrollView.insetsLayoutMarginsFromSafeArea = false;
webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
webView.translatesAutoresizingMaskIntoConstraints = NO;
self.view = webView;
UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
CGFloat topPadding = window.safeAreaInsets.top;
CGFloat bottomPadding = window.safeAreaInsets.bottom;
CGFloat leftPadding = window.safeAreaInsets.left;
CGFloat rightPadding = window.safeAreaInsets.right;
self.additionalSafeAreaInsets = UIEdgeInsetsMake(-topPadding, -leftPadding, -bottomPadding, -rightPadding);
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://apple.com"]]];
}
这不是完美的解决方案,但我设法通过将 webView 作为子视图添加到 self.view 并向 superview 而不是 safeArea 添加约束来获得相同的效果来解决这个问题。
解决方案:
- 将尾随约束连接到变量
- 设置约束已启用
false in viewDidLoad(优化设备方向检查)
- 在函数 webView(WKWebView, didFinish: WKNavigation) 中将约束 isEnabled 设置为 true
不要忘记注册到 webView 的 navigationDelegate
@IBOutlet var mainWebView: WKWebView!
@IBOutlet var trailingConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
let orientation = UIDevice.current.orientation
if orientation == .landscapeLeft || orientation == .landscapeRight {
trailingConstraint.isActive = false
}
mainWebView.navigationDelegate = self
mainWebView.load(URLRequest(url: URL(string: "https://apple.com")!))
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
trailingConstraint.isActive = true
}
这是它的样子:
#import "ViewController.h"
#import <WebKit/WebKit.h>
@implementation ViewController
- (void)loadView
{
WKWebView* webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:[[WKWebViewConfiguration alloc] init]];
self.view = webView;
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://apple.com"]]];
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
@end
这只会发生在设置了 viewport-fit=cover
的网站上。如果你在 Safari 中打开相同的网站,你可以看到第一个绘制框架有同样的问题,但它立即正确调整大小。
只有在横向启动时才会发生这种情况。 旋转到纵向并返回到横向解决了这个问题。即使最小化应用程序并再次打开它也能解决这个问题。
那么我可以通过代码做些什么来强制它自行修复吗?
我已经尝试调用 setNeedsLayout
和 layoutIfNeeded
到整个 WKWebView
树。设置 scroller insets 将使内容看起来像没有设置 viewport-fit=cover
。
这发生在 iOS 12 和 13(已测试)和 iOS 13 模拟器上。
您好,您需要更改视口。
请使用以下代码更改您的 "loadView" 函数。
- (void)loadView
{
NSString *jScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
WKUserContentController *wkUController = [[WKUserContentController alloc] init];
[wkUController addUserScript:wkUScript];
WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
wkWebConfig.userContentController = wkUController;
WKWebView* webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:wkWebConfig];
webView.insetsLayoutMarginsFromSafeArea = false;
webView.scrollView.insetsLayoutMarginsFromSafeArea = false;
webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
webView.translatesAutoresizingMaskIntoConstraints = NO;
self.view = webView;
UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
CGFloat topPadding = window.safeAreaInsets.top;
CGFloat bottomPadding = window.safeAreaInsets.bottom;
CGFloat leftPadding = window.safeAreaInsets.left;
CGFloat rightPadding = window.safeAreaInsets.right;
self.additionalSafeAreaInsets = UIEdgeInsetsMake(-topPadding, -leftPadding, -bottomPadding, -rightPadding);
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://apple.com"]]];
}
这不是完美的解决方案,但我设法通过将 webView 作为子视图添加到 self.view 并向 superview 而不是 safeArea 添加约束来获得相同的效果来解决这个问题。
解决方案:
- 将尾随约束连接到变量
- 设置约束已启用 false in viewDidLoad(优化设备方向检查)
- 在函数 webView(WKWebView, didFinish: WKNavigation) 中将约束 isEnabled 设置为 true
不要忘记注册到 webView 的 navigationDelegate
@IBOutlet var mainWebView: WKWebView! @IBOutlet var trailingConstraint: NSLayoutConstraint! override func viewDidLoad() { super.viewDidLoad() let orientation = UIDevice.current.orientation if orientation == .landscapeLeft || orientation == .landscapeRight { trailingConstraint.isActive = false } mainWebView.navigationDelegate = self mainWebView.load(URLRequest(url: URL(string: "https://apple.com")!)) } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { trailingConstraint.isActive = true }