Изменить размер IOS WKWebView при появлении клавиатуры - PullRequest
1 голос
/ 16 октября 2019

Я бы хотел изменить размер WKWebView, чтобы он размещался над клавиатурой как в альбомной, так и в книжной ориентации, а также чтобы пользователь мог переключаться между альбомной и книжной ориентацией во время использования клавиатуры. Я также хотел бы, чтобы размер WKWebView изменялся при исчезновении клавиатуры.

По умолчанию используется прокрутка WKWebView, чтобы используемое текстовое поле было видно над клавиатурой. Я хочу переопределить это поведение.

Я ожидаю, что мне придется добавить некоторый код, чтобы ответить на keyboardDidShow и keyboardDidHide, чтобы изменить GCRect, используемый WebView. Правильно ли использовать эти события?

Как получить доступ к высоте клавиатуры как в книжной, так и в альбомной ориентации?

Нужно ли добавлять к этому задержку или будет прокрутка по умолчанию? веб-просмотра уже произошло к тому времени, когда сработала клавиатураDidShow?

Когда я изменю размер GCRect веб-просмотра, вызовет ли это окно window.onresize в javascript?

Позволит ли это устройству работатьповернут, когда клавиатура используется, или мне нужно добавить дополнительный код, чтобы справиться с этим?

Спасибо за любую помощь, которую кто-нибудь может мне дать.

1 Ответ

0 голосов
/ 02 ноября 2019

Чтобы решить эту проблему, я добавил следующие объявления в 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 меньше высоты клавиатуры (которая передается в качестве единственного параметра ей).

Указывает на примечание

  1. Не реагируйте в javascript на window.onorientationchange или window.onresize
  2. Я создаю новый фрейм для веб-представления при вращении, но, делая это во время перехода, а затем вызывая код javascript по завершении,достаточно хорошо для меня.
  3. Первоначально я пытался создать новый кадр по завершении, но это вызвало у меня много проблем из-за нескольких миллисекунд, которые потребовались, и необходимости добавлять переменные задержки внутри javascript, чтобы ждать егослучилось.
  4. Я также попытался переместить создание нового кадра до поворота, но это вызвало проблемы с экраном запуска. Не показанный выше, у меня есть вид внутри контроллера представления, идентичный моему экрану запуска, который отображается на viewDidLoad, чтобы покрыть время, затраченное на загрузку html / css / javascript. Это удаляется, когда javascript сообщает, что он был загружен.
  5. Мне не нужно создавать новый фрейм, когда клавиатура появляется или удаляется, я просто сообщаю javascript не использовать скрытую область. Я обнаружил, что создание новых фреймов веб-просмотра имело те же проблемы с задержкой, что и выше.
  6. Обратите внимание, что это решение работает, когда вращение устройства с помощью клавиатуры видно.
...