Как исправить область просмотра при открытии виртуальной клавиатуры в мобильном Safari? - PullRequest
4 голосов
/ 10 января 2020

Цель

В мобильном Safari, когда виртуальная клавиатура открыта, экран должен отображаться так: enter image description here

где:

  • Навбар и ввод зафиксированы на месте
  • Список текстовых сообщений можно прокручивать

Проблема

На мобильном Safari, когда софт клавиатура открыта, перетаскивание на входе или навигационная панель могут перемещать весь видовой экран вверх и вниз.

У меня есть видео с экрана, демонстрирующее проблему: https://youtu.be/GStBjRVpoGU

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

Фон

Это приложение представляет собой гибридное мобильное приложение: построено как веб-приложение с React. js, но упаковано в приложение React Native с использованием компонента WebView. Тем не менее, такая же проблема существует, даже если веб-приложение открывается в обычном мобильном окне Safari.

Mobile Safari имеет связанную проблему, когда программная клавиатура при открытии открывает все окно просмотра, так что верхняя часть половина порта просмотра выталкивается вверх и за пределы экрана. Этот превосходный блог предоставляет и описание этой проблемы, и решение для нее. Я реализовал это решение. Он остановил перемещение окна просмотра вверх при открытии программной клавиатуры, но окно просмотра все еще может скользить после открытия программной клавиатуры.

Другая проблема заключается в том, что мобильный Safari не обновляет window.innerHeight, когда программная клавиатура открыто / закрыто. Чтобы обойти это, я использовал react-native-keyboard-spacer в приложении React Native, примерно так:

render() {
    return (
      <React.Fragment>
        <SafeAreaView >
          <WebView/>
        </SafeAreaView>
        <KeyboardSpacer />
      </React.Fragment>
    );
  }

Это изменяет высоту веб-просмотра при каждом открытии / закрытии программной клавиатуры, и, таким образом, window.innerHeight et c также меняется.

Также известно, что position: fixed; на мобильном Safari не работает так хорошо, когда программная клавиатура открыта, поэтому я использовал position: absolute; вместо этого, благодаря предложениям на этом Другой очень полезный блог .

Я создал песочницу с кодом , чтобы продемонстрировать проблему. Откройте его в мобильном Safari, чтобы увидеть слайд экрана после открытия виртуальной клавиатуры. Здесь вы также можете найти реальный код изолированной программной среды здесь , который представляет собой наиболее близкий пример решения этой проблемы.

Однако следует отметить одну вещь в изолированной программной среде кода. Там нет WebView или KeyboardSpacer: это просто веб-страница. Таким образом, мне пришлось жестко задавать некоторые высоты. Но если вы откроете его в мобильном Safari, вы увидите, что область просмотра скользит повсюду, когда открыта программная клавиатура.

Кто-нибудь видел эту конкретную проблема раньше? Как ты это починил? Большое спасибо заранее.

1 Ответ

1 голос
/ 12 февраля 2020

С помощью JMathew я нашел решение этой проблемы.

См. Пример рабочих кодов и коробки здесь .

  1. Поместите панель навигации, список сообщений и ввод в элементы div контейнера.
  2. Добавьте ссылки на эти элементы div контейнера. Например:
  const messageListContainerRef = useRef<HTMLDivElement>(null);

  //...

  return (
    //...
    <div ref={messageListContainerRef}>
      <MessageList/>
    </div>
    //...
  )
Когда виртуальная клавиатура открывается (когда фиктивный ввод сфокусирован), добавьте прослушиватель событий для события touchmove к inputContainerRef и navbarContainerRef. Используйте это для preventDefault() на событии сенсорного перемещения, что не позволит пользователю перемещать ввод и панель навигации вверх и вниз. Например:
if (inputContainerRef.current) {
  inputContainerRef.current.addEventListener('touchmove', (e) => {
    e.preventDefault();
  });
}
Вы по-прежнему хотите иметь возможность прокручивать список сообщений, поэтому вы не можете просто набрать preventDefault(). Вместо этого используйте это решение , чтобы пользователь не мог прокручивать страницу вниз (и верх) страницы, установив значение scrollTop:
if (messageListContainerRef.current) {
  messageListContainerRef.current.addEventListener('touchmove', (e: any) => {
    if (!e.currentTarget) {
      return;
    }
    if (e.currentTarget.scrollTop === 0) {
      e.currentTarget.scrollTop = 1;
    } else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop +
                                                e.currentTarget.offsetHeight) {
      e.currentTarget.scrollTop -= 1;
    }
  });
}

В зависимости от вашего хотите / нужно, вы можете установить эти touchmove прослушиватели событий при монтировании компонента, а не при фокусировке ввода. Вы можете даже установить их для всего document.body, если это работает для вас.

...