Чтобы решить эту проблему, я добавил следующие объявления в 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
- Я создаю новый фрейм для веб-представления при вращении, но, делая это во время перехода, а затем вызывая код javascript по завершении,достаточно хорошо для меня.
- Первоначально я пытался создать новый кадр по завершении, но это вызвало у меня много проблем из-за нескольких миллисекунд, которые потребовались, и необходимости добавлять переменные задержки внутри javascript, чтобы ждать егослучилось.
- Я также попытался переместить создание нового кадра до поворота, но это вызвало проблемы с экраном запуска. Не показанный выше, у меня есть вид внутри контроллера представления, идентичный моему экрану запуска, который отображается на viewDidLoad, чтобы покрыть время, затраченное на загрузку html / css / javascript. Это удаляется, когда javascript сообщает, что он был загружен.
- Мне не нужно создавать новый фрейм, когда клавиатура появляется или удаляется, я просто сообщаю javascript не использовать скрытую область. Я обнаружил, что создание новых фреймов веб-просмотра имело те же проблемы с задержкой, что и выше.
- Обратите внимание, что это решение работает, когда вращение устройства с помощью клавиатуры видно.