KeyboardAvoidingView无法正常工作

Cha*_*eja 37 react-native-android

KeyboardAvoidingView无法正常工作

我正在尝试使用KeyboardAvoidingView with behavior ="padding".

出于某种原因,当我尝试在TextInput中输入任何文本时,空间将位于TextInput下方.随附的是正在发生的事情以及代码.有没有人有任何想法在这里发生什么?

  render() {
    return (

      <KeyboardAvoidingView  style={{ flex: 1}}  behavior="padding">
      < View
          style={{
            flex: 1,

          backgroundColor: "#FFFFFF",

        }}
      >

        <ScrollView
          contentContainerStyle={{ justifyContent: "flex-end", flex: 1 }}>
                <ChatInfo />
              </ScrollView>


          <View style={styles.container}>
          <TextInput
            style={styles.input}
            underlineColorAndroid="transparent"
            autoCapitalize="none"
            onChangeText={text => this.setState({ text: text })}
            value={this.state.text}
          />

          <TouchableOpacity
            style={styles.submitButton}
            onPress={this.submitName}
          >
            <Text style={styles.submitButtonText}> SEND </Text>
          </TouchableOpacity>
        </View>

      </ View>
      </KeyboardAvoidingView>
    );
  }
}

export default connect()(ChatScreen);

const styles = StyleSheet.create({
  input: {
    margin: 2,
    paddingLeft: 15,
    flex: 1,
    height: 40,
    padding: 10,
    fontSize: 14,
    fontWeight: "400"
  },

      container: {
        borderTopWidth: 1,
        minWidth: "100%",
        borderColor: "#cccccc",
        height: 44,
        flexDirection: "row",
        justifyContent: "space-between",
        backgroundColor: "#fff"

      },

  submitButtonText: {
    color: "#0a9ffc",
    fontSize: 14,
    fontWeight: "500"
  },

  submitButton: {
    backgroundColor: "#fff",
    padding: 10,
    margin: 2,
    height: 40,
    alignItems: "center",
    justifyContent: "center"
  }
});
Run Code Online (Sandbox Code Playgroud)

Toh*_*oon 92

如果您正在使用react-navigation,则会受到react-navigation标题的影响.标题的高度在不同的移动屏幕上有所不同.所以你必须得到标题的高度并传递到keyboardVerticalOffset道具.

import { Header } from 'react-navigation';

<KeyboardAvoidingView
  keyboardVerticalOffset = {Header.HEIGHT + 20} // adjust the value here if you need more padding
  style = {{ flex: 1 }}
  behavior = "padding" >

  <ScrollView>
    <TextInput/>
    <TextInput/>
    <TextInput/>
    <TextInput/>
    <TextInput/>
    <TextInput/>
  </ScrollView> 

</KeyboardAvoidingView>
Run Code Online (Sandbox Code Playgroud)

  • 要在 @Hylle 上构建,对于功能组件,请使用 import { useHeaderHeight } from 'react-navigation-stack' ,然后使用 const headerHeight = useHeaderHeight() 。此外,不要使用任意数字,只需将高度相加,如下所示:“const KeyboardVerticalOffset = Constants.statusBarHeight + headerHeight”。如果您使用的是 InputAccessoryView,也请添加它的高度。 (6认同)
  • 为什么是47?????????? (3认同)
  • 对我来说,“ keyboardVerticalOffset = {Header.HEIGHT + 64}”是最佳选择。谢谢! (2认同)
  • 只是为了澄清一下:我仍然遇到一些问题,其中只有TextInput与_keyboard_关联(例如,如果我有一个Button或一个Text则不会提升)。为了解决这个问题,我将TextInput和Button(或其他任何东西)包装到View中。 (2认同)
  • 看来您需要从新包访问 Header,现在从“react-navigation-stack”导入 { Header }; (2认同)

小智 24

这是KeyboardAvoidingView和Android的已知问题.有多种方法可以解决此问题.

React Native文档说:

如果没有任何行为道具,Android可能表现得更好,而iOS则相反.

所以,如果你只使用Android,你可以删除行为道具,它应该立即工作.为了获得最佳效果,请添加android:windowSoftInputMode="adjustResize"到您的清单中.

或者,您可以给出一个适合您的偏移值: KeyboardAvoidingView keyboardVerticalOffset={-500} behavior="padding"

对于ios有条件地做同样的事情:

behavior= {(Platform.OS === 'ios')? "padding" : null}

keyboardVerticalOffset={Platform.select({ios: 0, android: 500})}

  • `Platform`现在有一个`select()`方法,所以你也可以这样做:`behavior = {Platform.select({android:undefined,ios:'padding'})}` (7认同)
  • 就我而言,我只能在两个平台上都将“行为”设置为“填充”才能使用此功能。在Android上将其设置为“ null”没有任何效果。 (2认同)

ful*_*ris 22

对于 2021 年来到这里的任何人,需要更新以下答案:

  • useHeaderHeight不再由 导出@react-navigation/stack,而是在@react-navigation/elements.

  • React Native现在还建议behavior为 iOS 和 Android设置该prop。所以完整的解决方案是:

import { useHeaderHeight } from '@react-navigation/elements';

export const MyComponent = () => {
  const headerHeight = useHeaderHeight();
  return (
      <KeyboardAvoidingView
        keyboardVerticalOffset={headerHeight}
        style={style.container}
        behavior={Platform.OS === "ios" ? "padding" : "height"}
      >
      {/* rest of your component */}
      </KeyboardAvoidingView>
    );
}
Run Code Online (Sandbox Code Playgroud)

我不需要向headerHeightin添加任何额外的值keyboardVerticalOffset,它在 iOS 和 Android 上运行得很好。

编辑:现在问题更加严重,因为KeyboardAvoidingView不支持所有类型的 Android 键盘。该解决方案必须依赖于打开键盘到特定元素(例如文本输入)。这个自定义组件看起来像这样:

import React, { PropsWithChildren, useEffect, useState } from 'react';
import { Platform, Animated, Dimensions, Keyboard, KeyboardAvoidingView, StyleSheet, TextInput } from 'react-native';
import {useHeaderHeight} from '@react-navigation/elements';
import { useKeyboard } from '@react-native-community/hooks';

export default function KeyboardShift (props: PropsWithChildren<{}>) {
  const [shift, setShift] = useState(new Animated.Value(0))
  const keyboard = useKeyboard()

  // On mount, add keyboard show and hide listeners
  // On unmount, remove them
  useEffect(() => {
    Keyboard.addListener('keyboardDidShow', handleKeyboardDidShow);
    Keyboard.addListener('keyboardDidHide', handleKeyboardDidHide);
    return () => {
      Keyboard.removeAllListeners('keyboardDidShow');
      Keyboard.removeAllListeners('keyboardDidHide');
    }
  }, [])

  const handleKeyboardDidShow = () => {
    const { height: windowHeight } = Dimensions.get('window');
    const keyboardHeight = keyboard.keyboardHeight;
    const currentlyFocusedInputRef = TextInput.State.currentlyFocusedInput();
    currentlyFocusedInputRef.measure((x, y, width, height, pageX, pageY) => {
      const fieldHeight = height;
      const fieldTop = pageY;
      const gap = (windowHeight - keyboardHeight) - (fieldTop + fieldHeight);
      if (gap >= 0) {
        return;
      }
      Animated.timing(
        shift,
        {
          toValue: gap,
          duration: 1000,
          useNativeDriver: true,
        }
      ).start();
    })
  }

  const handleKeyboardDidHide = () => {
    Animated.timing(
      shift,
      {
        toValue: 0,
        duration: 1000,
        useNativeDriver: true,
      }
    ).start();
  }

  const { children } = props;

  // Android: we need an animated view since the keyboard style can vary widely
  // And React Native's KeyboardAvoidingView isn't always reliable
  if (Platform.OS === 'android') {
    return (
      <Animated.View style={[styles.container, { transform: [{translateY: shift}] }]}>
        {children}
      </Animated.View>
    );
  }

  // iOS: React Native's KeyboardAvoidingView with header offset and 
  // behavior 'padding' works fine on all ios devices (and keyboard types)
  const headerHeight = useHeaderHeight();
  return (
    <KeyboardAvoidingView
      keyboardVerticalOffset={headerHeight}
      style={styles.container}
      behavior={'padding'}>
      {children}
    </KeyboardAvoidingView>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1
  }
});
Run Code Online (Sandbox Code Playgroud)

是的,不幸的是,它很冗长,但它可以为 iOS 和 Android 上的所有类型的手机完成工作。

在这里阅读更多相关信息。

第二次编辑:截至 2022 年 4 月 22 日,我已将上面的复杂解决方案替换为以下内容:

步骤1:

behavior={Platform.OS === "ios" ? "padding" : undefined}
Run Code Online (Sandbox Code Playgroud)

第2步:

请务必删除

android:windowSoftInputMode="adjustPan"
Run Code Online (Sandbox Code Playgroud)

(或任何windowSoftInputMode与此相关的内容)来自您的AndroidManifest.xml文件。

到目前为止,这个解决方案一直有效(并且代码更少 - 总是更好,对吧?)


小智 15

KeyboardAvoidingView必须是一个ScrollView孩子,而不是周围的其他方法。这样它表现正常(我使用它的目的是正常的)。试试吧,让我知道它是怎么回事。

<ScrollView>
    <KeyboardAvoidingView styles={styles.container} behavior='padding'>

    </KeyboardAvoidingView>
</ScrollView>
Run Code Online (Sandbox Code Playgroud)

  • 我不这么认为。在我的测试中,至少在 IOS 上作为 ScrollView 的父级工作得更好。 (3认同)
  • 这对我不起作用......实际上它与工作相反。 (3认同)

Bul*_*kel 9

警告

这似乎只是一个部分解决方案,虽然它最初工作,如果Android手机被锁定在屏幕上,键盘避免布局,当你解锁时最终再次使用键盘上方的额外填充.

TL;博士

android:windowSoftInputMode="adjustResize"从中删除AndroidManifest.xml

之前

...
<activity
  android:name=".MainActivity"
  android:label="@string/app_name"  
  android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
  android:windowSoftInputMode="adjustResize"
  >
...
Run Code Online (Sandbox Code Playgroud)

...
<activity
  android:name=".MainActivity"
  android:label="@string/app_name"  
  android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
  >
...
Run Code Online (Sandbox Code Playgroud)

为什么

如果我正确地理解了这个问题,我一直在处理同样的事情.通过android:windowSoftInputMode="adjustResize"在清单中,android系统将尝试做同样的工作KeyboardAvoidingView.这导致仅在Android上的键盘上方添加额外的间距.

如果在两个平台上工作,那么每次使用键盘输入时都要在iOS上处理这个问题,所以最好android:windowSoftInputMode="adjustResize"从清单中删除Android特定的行为并KeyboardAvoidingView每次使用.


小智 9

我认为这是因为行为道具的价值,所以我认为在键盘避免视图中添加这一行会有所帮助

<KeyboardAvoidingView
    style = {{ flex: 1 }}
    behavior={Platform.OS === "ios" ? "padding" : null}>
</KeyboardAvoidingView>
Run Code Online (Sandbox Code Playgroud)

  • `{Platform.OS ===“ios”?如果您使用 TypeScript,则为“padding”:未定义}` (2认同)

Ami*_*mit 9

KeyboardAvoidingView 的主要问题是;缺乏对其工作原理的理解。

我发现下面的链接非常有帮助

https://medium.com/@nickyang0501/keyboardavoidingview-not-working-properly-c413c0a200d4

  1. 首先,在 KeyboardAvoidingView 中使用 flex:1 和行为:'padding'
  2. 接下来是在“MainView”中使用 flex:1 ,它需要进入 KeyboardAvoidingView
  3. 最后是将 justifyContent: "flex-end" 添加到 ""MainView""

希望能帮助到你


Sco*_*ott 6

对于 React Native Navigation v5,您可以使用以下内容:

import { useHeaderHeight } from '@react-navigation/stack';

...

const Component = () => (

<KeyboardAvoidingView
  keyboardVerticalOffset={ useHeaderHeight() } // <-- for v5
  behavior="padding"
  style={{ flex: 1 }}
>
  <TextInput
    style={{ height: 30, width: "100%, borderWidth: 1 }}
  />
</KeyboardAvoidingView

)
Run Code Online (Sandbox Code Playgroud)

https://reactnavigation.org/docs/stack-navigator#headertransparent