KeyboardAvoidingView无法正常工作

时间:2018-01-24 10:42:07

标签: react-native-android

KeyboardAvoidingView无法正常工作

我正在尝试将KeyboardAvoidingView与behavior="padding"一起使用。

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

Whats-App-Image-2018-01-24-at-5-07-46-PM

  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"
  }
});

18 个答案:

答案 0 :(得分:60)

如果您使用反应导航,这会受到反应导航标题的影响。标头的高度在不同的移动屏幕上有所不同。因此,您必须获取标题的高度并将其传递给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>

答案 1 :(得分:14)

这是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})}

答案 2 :(得分:6)

警告

这似乎只是部分解决方案,尽管它最初可以工作,但是如果使用避免键盘布局的键盘将android手机锁定在屏幕上,则在解锁时最终会再次在键盘上方出现多余的填充。

tl; dr

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

之前

...
<activity
  android:name=".MainActivity"
  android:label="@string/app_name"  
  android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
  android:windowSoftInputMode="adjustResize"
  >
...

之后

...
<activity
  android:name=".MainActivity"
  android:label="@string/app_name"  
  android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
  >
...

为什么

如果我正确理解了该问题,那么我一直在处理同一件事。通过在清单中添加android:windowSoftInputMode="adjustResize",Android系统将尝试执行与KeyboardAvoidingView相同的工作。这导致仅在Android键盘上方添加额外的间距。

如果在两个平台上都可以使用,则每次使用键盘输入时都必须在iOS上进行处理,因此最好通过清单中的android:windowSoftInputMode="adjustResize"并使用{{ 1}}。

答案 3 :(得分:4)

这里的许多答案都显示了条件行为道具。这样。

// incorrect ?
<KeyboardAvoidingView
    style = {{ flex: 1 }}
    behavior={Platform.OS === "ios" ? "padding" : null}>
</KeyboardAvoidingView>

但是这会将behavior道具在Android上设置为null。

The documentation says...

Android和iOS与该道具的交互方式不同。
如果完全不提供行为支持,Android可能会表现更好,而iOS则相反。

有条件地展开behavior道具可提供精确的解决方案。
它在iOS上添加了道具,而在Android上却保留了它。

// correct ?
<KeyboardAvoidingView
    style = {{ flex: 1 }}
    {...(Platform.OS === 'ios' && { behavior: 'padding' })}
</KeyboardAvoidingView>

这是一个解决方案,如果使用styled-components且在Android上不使用不必要的KeyboardAvoidingView。

import { KeyboardAvoidingView as Kav, Platform, View } from 'react-native';
import styled from 'styled-components/native';

// If ios we change the component type and, via the `attrs` method, add a behavior prop. This
// approach leaves Android alone. Because it already works.
export const ScreenContainer = styled(Platform.OS === 'ios' ? Kav : View).attrs({
  behavior: Platform.OS === 'ios' && 'padding',
})`
  flex: 1;
`;

答案 4 :(得分:3)

KeyboardAvoidingView必须是ScrollView孩子,而不是相反。这样它的行为正常(正常我用它的目的)。试一试,让我知道它是怎么回事。

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

    </KeyboardAvoidingView>
</ScrollView>

答案 5 :(得分:2)

对于 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

)

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

答案 6 :(得分:2)

<KeyboardAvoidingView behavior={Platform.OS === "ios" ? "padding" : null} 
style={{flex: 1 }}>

在上面的代码段中,flex设置为1,即使没有打开键盘,默认情况下也会在键盘上方呈现文本输入字段。而且,当键盘弹出时,输入字段会因键盘高度的偏移而进一步向上推。

将flex设置为0可以解决此问题,就像我的情况一样。

 <KeyboardAvoidingView behavior={Platform.OS === "ios" ? "padding" : null} 
  style={{flex: 0 }}>
  <View>
   ...
  </View>
 </KeyboardAvoidingView>

答案 7 :(得分:2)

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“”

希望有帮助

答案 8 :(得分:2)

我认为这是因为behavior props value,所以我认为在Keyboardavoidview中添加这一行会有所帮助

<KeyboardAvoidingView
    style = {{ flex: 1 }}
    behavior={Platform.OS === "ios" ? "padding" : null}>
</KeyboardAvoidingView>

答案 9 :(得分:2)

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

        <View>
          ....
        </View>

   </ScrollView>
</KeyboardAvoidingView>

答案 10 :(得分:1)

我认为最好的方法是为此创建一个HOC,此外,通过使用react-native-iphone-x-helper中的getBottomSpace,您可以解决iPhone X和...的重叠问题。

        def update51P(self, obj):
            app = MDApp.get_running_app()
            print(app.Alpick51P)
            print(app.Aldelay51P)
            print(app.Trpick51P)
            print(app.InverseCurve)

答案 11 :(得分:1)

应用 ScrollView 后,问题就解决了。

答案 12 :(得分:0)

 <KeyboardAvoidingView style={styles.keyboardcontainer} behavior="padding"
       keyboardVerticalOffset={Platform.select({ios :120, android : 500})}
       enabled>

    <View  style={{flex: 1 }}>
        // Your Code 
    </View>

</KeyboardAvoidingView>

答案 13 :(得分:0)

我的问题是使用keyboardHidesTabBar选项。以下设置对我有用:

const AppBottomTabNavigator = createBottomTabNavigator(
  {
    ...
  },
  {
    tabBarOptions: {
      keyboardHidesTabBar: Platform.OS !== 'ios',
    },
  },
);

组件:

import React from 'react';
import {
  Keyboard,
  KeyboardAvoidingView,
  Platform,
  StyleSheet,
  Text,
  TextInput,
  TouchableWithoutFeedback,
  View,
} from 'react-native';
import { Header } from 'react-navigation-stack';

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  center: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  textInput: {
    height: 40,
    borderColor: 'gray',
    borderWidth: 1,
  },
});

const MyScreen = () => {
  return (
    <KeyboardAvoidingView
      behavior={Platform.OS === 'ios' ? 'padding' : null}
      keyboardVerticalOffset={Header.HEIGHT}
      style={styles.container}
    >
      <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
        <View style={styles.container}>
          <View style={[styles.container, styles.center]}>
            <Text>Hello!</Text>
          </View>
          <TextInput style={styles.textInput} placeholder="Message" />
        </View>
      </TouchableWithoutFeedback>
    </KeyboardAvoidingView>
  );
};

export default MyScreen;

答案 14 :(得分:0)

我的问题不是检查此平台类型

将以下代码添加到KeyboardAvoidView中为我修复了

behavior={Platform.OS === "ios" ? "padding" : 'height'}

答案 15 :(得分:0)

虽然它不是一个正确的答案,但是有一个非常流行的库可以解决这种类型的问题,它被称为可以在具有可用键盘区域的情况下使用scrollview。您可以通过以下链接查看 https://www.npmjs.com/package/react-native-keyboard-aware-scrollview

答案 16 :(得分:0)

我遇到了类似的问题,因为我正在使用带有底部标签的#include <cstdio> #include <Windows.h> // Windows multimedia device #include <Mmdeviceapi.h> #include <Functiondiscoverykeys_devpkey.h> // WASAPI #include <Audiopolicy.h> #include <Audioclient.h> #include <random> class Noise_Gen { public: Noise_Gen() : format(), engine(__rdtsc()), float_dist(-1.f, 1.f) {}; void SetFormat(WAVEFORMATEX* wfex) { if(wfex->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { format = *reinterpret_cast<WAVEFORMATEXTENSIBLE*>(wfex); } else { format.Format = *wfex; format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; INIT_WAVEFORMATEX_GUID(&format.SubFormat, wfex->wFormatTag); format.Samples.wValidBitsPerSample = format.Format.wBitsPerSample; format.dwChannelMask = 0; } } // (The size of an audio frame = nChannels * wBitsPerSample) void FillBuffer(UINT32 bufferFrameCount, BYTE* pData, DWORD* flags) { const UINT16 formatTag = EXTRACT_WAVEFORMATEX_ID(&format.SubFormat); if(formatTag == WAVE_FORMAT_IEEE_FLOAT) { float* fData = (float*)pData; for(UINT32 i = 0; i < format.Format.nChannels * bufferFrameCount; i++) { fData[i] = float_dist(engine); } } else if(formatTag == WAVE_FORMAT_PCM) { using rndT = decltype(engine)::result_type; UINT32 iterations = format.Format.nBlockAlign * bufferFrameCount / sizeof(rndT); UINT32 leftoverBytes = format.Format.nBlockAlign * bufferFrameCount % sizeof(rndT); rndT* iData = (rndT*)pData; UINT32 i = 0; for(; i < iterations; i++) { iData[i] = engine(); } if(leftoverBytes != 0) { rndT lastRnd = engine(); BYTE* pLastBytes = pData + i * sizeof(rndT); for(UINT32 j = 0; j < leftoverBytes; ++j) { pLastBytes[j] = lastRnd >> (j * 8) & 0xFF; } } } else { //memset(pData, 0, wfex.Format.nBlockAlign * bufferFrameCount); *flags = AUDCLNT_BUFFERFLAGS_SILENT; } } private: WAVEFORMATEXTENSIBLE format; std::mt19937_64 engine; std::uniform_real_distribution<float> float_dist; }; // REFERENCE_TIME time units per second and per millisecond #define REFTIMES_PER_SEC 10000000ll #define REFTIMES_PER_MILLISEC 10000 #define EXIT_ON_ERROR(hres) \ if (FAILED(hres)) { goto Exit; } #define SAFE_RELEASE(punk) \ if ((punk) != NULL) \ { (punk)->Release(); (punk) = NULL; } HRESULT PlayAudioStream(Noise_Gen* pMySource) { HRESULT hr; REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC; REFERENCE_TIME hnsActualDuration; IMMDeviceEnumerator* pEnumerator = NULL; IPropertyStore* pPropertyStore = NULL; IMMDevice* pDevice = NULL; IAudioClient* pAudioClient = NULL; IAudioRenderClient* pRenderClient = NULL; WAVEFORMATEX* pwfx = NULL; UINT32 bufferFrameCount; BYTE* pData; DWORD flags = 0; PROPVARIANT name; hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, IID_PPV_ARGS(&pEnumerator)); EXIT_ON_ERROR(hr); hr = pEnumerator->GetDefaultAudioEndpoint( eRender, eConsole, &pDevice); EXIT_ON_ERROR(hr); hr = pDevice->OpenPropertyStore(STGM_READ, &pPropertyStore); EXIT_ON_ERROR(hr); PropVariantInit(&name); hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &name); EXIT_ON_ERROR(hr); printf("%S", name.pwszVal); printf("\n"); hr = pDevice->Activate(__uuidof(pAudioClient), CLSCTX_ALL, NULL, (void**) &pAudioClient); EXIT_ON_ERROR(hr); hr = pAudioClient->GetMixFormat(&pwfx); EXIT_ON_ERROR(hr); hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, hnsRequestedDuration, 0, pwfx, NULL); EXIT_ON_ERROR(hr); // Tell the audio source which format to use. pMySource->SetFormat(pwfx); // Get the actual size of the allocated buffer. hr = pAudioClient->GetBufferSize(&bufferFrameCount); EXIT_ON_ERROR(hr); hr = pAudioClient->GetService(IID_PPV_ARGS(&pRenderClient)); EXIT_ON_ERROR(hr); // Grab the entire buffer for the initial fill operation. hr = pRenderClient->GetBuffer(bufferFrameCount, &pData); EXIT_ON_ERROR(hr); // Load the initial data into the shared buffer. pMySource->FillBuffer(bufferFrameCount, pData, &flags); hr = pRenderClient->ReleaseBuffer(bufferFrameCount, flags); EXIT_ON_ERROR(hr); // Calculate the actual duration of the allocated buffer. hnsActualDuration = REFTIMES_PER_SEC * bufferFrameCount / pwfx->nSamplesPerSec; hr = pAudioClient->Start(); // Start playing. EXIT_ON_ERROR(hr); // Each loop fills about half of the shared buffer. DWORD sleepTime; while(flags != AUDCLNT_BUFFERFLAGS_SILENT) { // Sleep for half the buffer duration. sleepTime = (DWORD) (hnsActualDuration / REFTIMES_PER_MILLISEC / 2); if(sleepTime != 0) Sleep(sleepTime); // See how much buffer space is available. UINT32 numFramesPadding; hr = pAudioClient->GetCurrentPadding(&numFramesPadding); EXIT_ON_ERROR(hr); UINT32 numFramesAvailable = bufferFrameCount - numFramesPadding; // Grab all the available space in the shared buffer. hr = pRenderClient->GetBuffer(numFramesAvailable, &pData); EXIT_ON_ERROR(hr); // Get next 1/2-second of data from the audio source. pMySource->FillBuffer(numFramesAvailable, pData, &flags); hr = pRenderClient->ReleaseBuffer(numFramesAvailable, flags); EXIT_ON_ERROR(hr); } // Wait for last data in buffer to play before stopping. sleepTime = (DWORD) (hnsActualDuration / REFTIMES_PER_MILLISEC / 2); if(sleepTime != 0) Sleep(sleepTime); hr = pAudioClient->Stop(); // Stop playing. EXIT_ON_ERROR(hr); Exit: CoTaskMemFree(pwfx); SAFE_RELEASE(pRenderClient); SAFE_RELEASE(pAudioClient); SAFE_RELEASE(pDevice); SAFE_RELEASE(pPropertyStore); // you forgot to free the property store SAFE_RELEASE(pEnumerator); return hr; } int main() { HRESULT hr = CoInitialize(nullptr); if(FAILED(hr)) { return hr; } Noise_Gen ng; PlayAudioStream(&ng); CoUninitialize(); }

@react-navigation开始,您可以通过以下两种方式之一来获取底部标签栏的高度(API reference):

"@react-navigation/bottom-tabs": "^5.11.2"

import { BottomTabBarHeightContext } from '@react-navigation/bottom-tabs';

// ...

<BottomTabBarHeightContext.Consumer>
 {tabBarHeight => (
   /* render something */
 )}
</BottomTabBarHeightContext.Consumer>

,然后将其设置为import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs'; // ... const tabBarHeight = useBottomTabBarHeight(); 的偏移量:

KeyboardAvoidingView

答案 17 :(得分:0)

请记住始终是您的顶级父级,具有 flex:1 然后子级是您的文本输入容器,如果您使用此方法,则它始终是其测试方法。

<KeyboardAvoidingView style={{  flex: 1 }}
    behavior={Platform.OS === "ios" ? "position" : null} enabled>
      <ScrollView>
        <View>
          <View >
            <Text maxFontSizeMultiplier={1.5} >
              Sign in to your account{" "}
            </Text>
             <View
                behavior="padding"
                enabled
              >
                <TextInput
                  placeholder="Email address"
                  placeholderTextColor={Colors.grey}
                  style={styles.textInput}
                  onChangeText={(e) => setEmail(e.trim())}
                  autoCapitalize="none"
                  returnKeyType={"done"}
                />
              </View>
        </View>
      </ScrollView>
</KeyboardAvoidingView>