出现键盘时调整 IOS WKWebView 的大小
Resize IOS WKWebView when keyboard appears
我想调整 WKWebView 的大小以适应横向和纵向的键盘上方,并在使用键盘时处理用户在横向和纵向之间的切换。我还希望在键盘消失时调整 WKWebView 的大小。
默认行为是滚动 WKWebView,以便使用中的文本字段在键盘上方可见。我想覆盖此行为。
我希望我必须添加一些代码来响应 keyboardDidShow 和 keyboardDidHide,以更改 WebView 使用的 GCRect。这些事件是否正确?
如何访问纵向和横向键盘的高度?
我是否必须为此添加延迟,或者 webview 的默认滚动是否在 keyboardDidShow 触发时已经发生?
当我更改 webview GCRect 大小时,这会触发 javascript 中的 window.onresize 吗?
这样做是否允许在使用键盘时旋转设备,或者我是否需要添加更多代码来处理这个问题?
感谢任何人能给我的帮助。
为了解决这个问题,我在 ViewController.h
中添加了以下声明
int appH ; // device width
int appW ; // device height
int keyH ; // keyboard height
int topMargin ; // safe area size at top of screen
int bottomMargin ; // safe area size at bottom of screen
bool smallScreen ; // whether want to see status bar in landscape
我希望我应该将这些声明为我的 ViewController 对象的属性,但这与答案无关
然后我按如下方式创建网络视图
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:(BOOL)animated];
NSString *deviceType = [UIDevice currentDevice].model;
smallScreen = [deviceType hasPrefix:@"iPhone"];
WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
[theConfiguration.userContentController addScriptMessageHandler:self name:@"MyApp"];
[theConfiguration.preferences setValue:@"TRUE" forKey:@"allowFileAccessFromFileURLs"];
// note that in viewDidLoad safeAreaInsets is set to zero
topMargin = [UIApplication sharedApplication].statusBarFrame.size.height ;
if (@available(iOS 11, *)) topMargin = self.view.safeAreaInsets.top ;
bottomMargin = 0 ;
if (@available(iOS 11, *)) bottomMargin = self.view.safeAreaInsets.bottom ;
int top = (smallScreen && appW > appH)? 0 : topMargin ;
int height = (smallScreen && appW > appH)? appH : appH - topMargin - bottomMargin ;
webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, top , appW, height) configuration:theConfiguration];
webView.navigationDelegate = self;
webView.UIDelegate = self;
然后我对大小的变化做出如下反应
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
// code here executes before rotation
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
// code here executes during rotation
appH = size.height ;
appW = size.width ;
int top = (smallScreen && appW > appH)? 0 : topMargin ;
int height = (smallScreen && appW > appH)? appH : appH - topMargin - bottomMargin ;
webView.frame = CGRectMake(0, top , appW, height);
}
completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
// code here executes after rotation
[webView evaluateJavaScript:@"IOSOrientationChanged()" completionHandler:nil];
}
];
}
我也注册键盘事件通知如下
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
并以这种方式回应这些
- (void)keyboardWillShow: (NSNotification *) notif
{
keyH = [notif.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height ;
NSString *javascriptString ;
javascriptString = [NSString stringWithFormat:@"IOSKeyboardChanged(%d)",keyH];
[webView evaluateJavaScript:javascriptString completionHandler:nil];
}
- (void)keyboardWillHide: (NSNotification *) notif
{
[webView evaluateJavaScript:@"IOSKeyboardChanged(0)" completionHandler:nil];
}
在上面的部分中,我提到了两个 Javascript 函数
IOSOrientationChanged 根据 window.innerWidth 和 window.innerHeight 中找到的屏幕大小重绘应用程序内容。
IOSKeyboard Changed 做同样的事情,但使用 window.innerHeight 减去键盘的高度(作为唯一参数传递给它)。
注意事项
- 不要在 javascript 中对 window.onorientationchange 或 window.onresize
做出反应
- 我在旋转时为 Web 视图创建了一个新框架,但是通过在转换期间执行此操作然后在完成时调用 javascript 代码,这对我来说已经足够了。
- 我最初尝试在完成时创建一个新框架,但这给我带来了很多问题,因为这花费了几毫秒,并且需要在 javascript 内添加可变延迟以等待它发生。
- 我还尝试将新框架的创建移动到旋转之前,但这会导致启动屏幕出现问题。上面没有显示,我有一个与我的启动屏幕相同的视图控制器内部视图,它显示在 viewDidLoad 上以涵盖加载 html/css/javascript 所花费的时间。当 javascript 报告它已加载时,它会被删除。
- 我不需要在键盘出现或移除时创建新的框架,我只是通知 javascript 不要使用隐藏区域。我发现在这里创建新的 web view frames 有和上面一样的时间延迟问题。
- 请注意,当使用键盘旋转设备可见时,此解决方案有效。
更新 IOS 13.3.1
更新到这个版本后,我发现上面的代码不足以防止网页视图偶尔滚动部分看不见。请注意"occasionally"。大部分时间代码都像以前一样工作,但是偶尔出现的问题足以保证修复,为此我做了以下工作:
添加到ViewController界面声明
UIScrollViewDelegate
创建网络视图后添加以下行
webView.scrollView.delegate = 自己;
另加
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[滚动视图setContentOffset:CGPointMake(0,0)];
};
我想调整 WKWebView 的大小以适应横向和纵向的键盘上方,并在使用键盘时处理用户在横向和纵向之间的切换。我还希望在键盘消失时调整 WKWebView 的大小。
默认行为是滚动 WKWebView,以便使用中的文本字段在键盘上方可见。我想覆盖此行为。
我希望我必须添加一些代码来响应 keyboardDidShow 和 keyboardDidHide,以更改 WebView 使用的 GCRect。这些事件是否正确?
如何访问纵向和横向键盘的高度?
我是否必须为此添加延迟,或者 webview 的默认滚动是否在 keyboardDidShow 触发时已经发生?
当我更改 webview GCRect 大小时,这会触发 javascript 中的 window.onresize 吗?
这样做是否允许在使用键盘时旋转设备,或者我是否需要添加更多代码来处理这个问题?
感谢任何人能给我的帮助。
为了解决这个问题,我在 ViewController.h
中添加了以下声明int appH ; // device width
int appW ; // device height
int keyH ; // keyboard height
int topMargin ; // safe area size at top of screen
int bottomMargin ; // safe area size at bottom of screen
bool smallScreen ; // whether want to see status bar in landscape
我希望我应该将这些声明为我的 ViewController 对象的属性,但这与答案无关
然后我按如下方式创建网络视图
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:(BOOL)animated];
NSString *deviceType = [UIDevice currentDevice].model;
smallScreen = [deviceType hasPrefix:@"iPhone"];
WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
[theConfiguration.userContentController addScriptMessageHandler:self name:@"MyApp"];
[theConfiguration.preferences setValue:@"TRUE" forKey:@"allowFileAccessFromFileURLs"];
// note that in viewDidLoad safeAreaInsets is set to zero
topMargin = [UIApplication sharedApplication].statusBarFrame.size.height ;
if (@available(iOS 11, *)) topMargin = self.view.safeAreaInsets.top ;
bottomMargin = 0 ;
if (@available(iOS 11, *)) bottomMargin = self.view.safeAreaInsets.bottom ;
int top = (smallScreen && appW > appH)? 0 : topMargin ;
int height = (smallScreen && appW > appH)? appH : appH - topMargin - bottomMargin ;
webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, top , appW, height) configuration:theConfiguration];
webView.navigationDelegate = self;
webView.UIDelegate = self;
然后我对大小的变化做出如下反应
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
// code here executes before rotation
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
// code here executes during rotation
appH = size.height ;
appW = size.width ;
int top = (smallScreen && appW > appH)? 0 : topMargin ;
int height = (smallScreen && appW > appH)? appH : appH - topMargin - bottomMargin ;
webView.frame = CGRectMake(0, top , appW, height);
}
completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
// code here executes after rotation
[webView evaluateJavaScript:@"IOSOrientationChanged()" completionHandler:nil];
}
];
}
我也注册键盘事件通知如下
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
并以这种方式回应这些
- (void)keyboardWillShow: (NSNotification *) notif
{
keyH = [notif.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height ;
NSString *javascriptString ;
javascriptString = [NSString stringWithFormat:@"IOSKeyboardChanged(%d)",keyH];
[webView evaluateJavaScript:javascriptString completionHandler:nil];
}
- (void)keyboardWillHide: (NSNotification *) notif
{
[webView evaluateJavaScript:@"IOSKeyboardChanged(0)" completionHandler:nil];
}
在上面的部分中,我提到了两个 Javascript 函数
IOSOrientationChanged 根据 window.innerWidth 和 window.innerHeight 中找到的屏幕大小重绘应用程序内容。
IOSKeyboard Changed 做同样的事情,但使用 window.innerHeight 减去键盘的高度(作为唯一参数传递给它)。
注意事项
- 不要在 javascript 中对 window.onorientationchange 或 window.onresize 做出反应
- 我在旋转时为 Web 视图创建了一个新框架,但是通过在转换期间执行此操作然后在完成时调用 javascript 代码,这对我来说已经足够了。
- 我最初尝试在完成时创建一个新框架,但这给我带来了很多问题,因为这花费了几毫秒,并且需要在 javascript 内添加可变延迟以等待它发生。
- 我还尝试将新框架的创建移动到旋转之前,但这会导致启动屏幕出现问题。上面没有显示,我有一个与我的启动屏幕相同的视图控制器内部视图,它显示在 viewDidLoad 上以涵盖加载 html/css/javascript 所花费的时间。当 javascript 报告它已加载时,它会被删除。
- 我不需要在键盘出现或移除时创建新的框架,我只是通知 javascript 不要使用隐藏区域。我发现在这里创建新的 web view frames 有和上面一样的时间延迟问题。
- 请注意,当使用键盘旋转设备可见时,此解决方案有效。
更新 IOS 13.3.1
更新到这个版本后,我发现上面的代码不足以防止网页视图偶尔滚动部分看不见。请注意"occasionally"。大部分时间代码都像以前一样工作,但是偶尔出现的问题足以保证修复,为此我做了以下工作:
添加到ViewController界面声明
UIScrollViewDelegate
创建网络视图后添加以下行
webView.scrollView.delegate = 自己;
另加
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{ [滚动视图setContentOffset:CGPointMake(0,0)]; };