KeyboardAvoidingView - высота Reset при скрытой клавиатуре

Я использую React Natives KeyboardAvoidingView, чтобы установить высоту моего View, когда отображается клавиатура. Но когда я закрываю клавиатуру в приложении, высота представления не возвращается обратно к исходному значению.

<KeyboardAvoidingView behavior="height" style={styles.step}>
  <View style={styles.stepHeader}>
    // my content
  </View>
</KeyboardAvoidingView>

Вид с красным контуром занял все пространство, прежде чем я открыл и закрыл клавиатуру.

Снимок экрана

Ответ 1

Более подробное объяснение ответа Нисарга.

Создайте ключ для KeyboardAvoidingView в конструкторе

constructor(props) {
    this.state = {
      keyboardAvoidingViewKey: 'keyboardAvoidingViewKey',
    }
}

добавить слушатель на клавиатуре будет/действительно скрыть (и удалить его в волеизключении)

import { KeyboardAvoidingView, Keyboard, Platform } from 'react-native'

componentDidMount() {
    // using keyboardWillHide is better but it does not work for android
    this.keyboardHideListener = Keyboard.addListener(Platform.OS === 'android' ? 'keyboardDidHide': 'keyboardWillHide', this.keyboardHideListener.bind(this));
}

componentWillUnmount() {
    this.keyboardHideListener.remove()
}

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

keyboardHideListener() {
    this.setState({
        keyboardAvoidingViewKey:'keyboardAvoidingViewKey' + new Date().getTime()
    });
}

render() {
    let { keyboardAvoidingViewKey } = this.state
    return (
        <KeyboardAvoidingView behavior={'height'} key={keyboardAvoidingViewKey} style={...}>
            ...
        </KeyboardAvoidingView>
    )
}

Примечание: имейте в виду, что это будет воссоздавать элементы внутри KeyboardAvoidingView (то есть: будет вызывать их функцию constructor, я не совсем уверен, почему, я обновлю ответ после более глубокого исследования), так что вам придется отслеживать любого значения состояния/пропа, которые могут быть перезаписаны

Обновить

После гораздо более глубокого исследования я теперь знаю, почему представления воссоздаются, когда вы меняете ключ. Чтобы по-настоящему понять, почему это происходит, нужно знать, как реагирующий-нативный отправляет команды рендеринга нативной стороне, это конкретное объяснение довольно длинное, и если оно вас интересует, вы можете прочитать мой ответ здесь. Короче говоря, response-native использует Reactjs для сравнения изменений, которые должны быть отображены, затем эти различия отправляются в виде команд компоненту с именем UIManager, который отправляет императивные команды, которые преобразуются в дерево макетов, которое меняет макет на основе команд diff, После того, как вы установили ключ для компонента, activjs использует этот ключ для определения изменений в указанном компоненте. Если этот ключ изменяется, реагирует, что компонент идентифицирует компонент как совершенно новый, который, в свою очередь, отправляет начальную команду для создания указанного компонента, делая все это дочерние элементы, которые будут созданы с нуля, потому что они идентифицируются как новые элементы в новом дереве макета, удаляя старое дерево и создавая новое вместо простой настройки различий.

Если вы хотите, вы можете шпионить за этими отправленными сообщениями, добавив следующий код в ваш файл App.js:

import MessageQueue from 'react-native/Libraries/BatchedBridge/MessageQueue'
const spyFunction = (msg) => {
    console.log(msg);
};

MessageQueue.spy(spyFunction);

Если вы сделаете это, в журналах вы заметите, что при каждом изменении ключа возвращаемая createViews - это createViews, которая, как указано выше, создает все элементы, вложенные в указанный компонент.

Ответ 2

Пожалуйста, дайте ключ KeyboardAvoidingView и измените, когда клавиатура открыта и закрыта, чтобы она отображалась и занимала высоту.

<KeyboardAvoidingView behavior="height" style={styles.step} key={values}>

Ответ 3

Оберните компоненты в <KeyboardAvoidingView behavior="padding" style={styles}> на iOS и <View style={styles}> на Android

render() {
    const ScrollContainer: View | KeyboardAvoidingView = 
    this.renderDependingOnPlatform();
    const scrollContainerParams: any = {};
    if (isIOS)
        scrollContainerParams.behavior = "padding";
return (
<ScrollContainer style={styles.container} {...scrollContainerParams}>
Scroll and other components
</ScrollContainer>
)}

/**
 * Render scroll container depending on platform
 * @returns {any}
 */
renderDependingOnPlatform() {
    if (isAndroid())
        return View;
    else return KeyboardAvoidingView;
}

Ответ 4

Простой обходной путь - установить для свойства behavior KeyboardAvoidingView значение padding. Это позволяет избежать вызова функции constructor, которая позволяет безопасно хранить информацию в состоянии (скажем, у вас есть два Input и вы хотите сохранить значение текста в состоянии, даже если пользователь сворачивает клавиатуру между нажатиями двух входов).

Этот метод может немного изменить макет дочерних элементов KeyboardAvoidingView, поэтому имейте это в виду.