【问题标题】:React Native - How to make KeyboardAvoidingView inside a ScrollView work for all devices?React Native - 如何使 ScrollView 中的 KeyboardAvoidingView 适用于所有设备?
【发布时间】:2019-11-14 22:14:11
【问题描述】:

我正在构建一个响应原生的聊天 UI,并且在 ScrollView 中使用 KeyboardAvoidingView 时遇到问题。选择 TextInput 时,输入字段和键盘之间的高度似乎因我使用的设备而异。我如何对其进行标准化,以使其对所有设备都同样有效?

import React from 'react'
import { StyleSheet, View, Text, TextInput, ScrollView, KeyboardAvoidingView, Platform } from 'react-native'
import Message from './message'


export default class Messages extends React.Component {
  static navigationOptions = ({ navigation }) => ({
    headerTitle: 'Messages',
    headerStyle: {
      backgroundColor: 'rgb(0,0,0)',
    },
    headerTitleStyle: {
      fontSize: 20,
      color: 'rgb(255,255,255)'
    },
    headerTintColor: 'rgb(0,122,255)',
  })

  state = {
    messages: [
      {
        message: 'yeah its not working',
        userId: 1,
        userName: 'Client'
      },
      {
        message: 'what isnt working...',
        userId: 2,
        userName: 'Sean'
      },
      {
        message: 'it, all of it',
        userId: 1,
        userName: 'Client'
      },
      {
        message: 'were on it',
        userId: 3,
        userName: 'Matt'
      },
      {
        message: 'fjdklsajfklsdjafkdjslkafjkdsjal;fdks;lajfdklsjldjskfja;sfjasdfjasdjlkfaj',
        userId: 3,
        userName: 'Matt'
      },
      {
        message: 'great!',
        userId: 1,
        userName: 'Client'
      },
      {
        message: 'blah',
        userId: 1,
        userName: 'Client'
      },
      {
        message: 'derp',
        userId: 2,
        userName: 'Sean'
      },
      {
        message: 'merh!',
        userId: 2,
        userName: 'Sean'
      },
       {
        message: 'help pls',
        userId: 2,
        userName: 'Sean'
      },
    ]
  }

  renderMessages = (messages) => {
    return messages.map((data, i) => <Message data={data} key={i}/>)
  } 

  render() {
    return (
      <ScrollView 
        style={styles.container}
        ref={ref => this.scrollView = ref}
        onContentSizeChange={(contentWidth, contentHeight)=> {this.scrollView.scrollToEnd({animated: true})}}
      >
        <KeyboardAvoidingView
          behavior={Platform.OS == 'ios' ? "position" : null}
        >
          <View>
              {this.renderMessages(this.state.messages)}
              <View style={styles.textBox}>
                <TextInput 
                  style={styles.textInput}
                  placeholder='Reply...'
                  placeholderTextColor={'rgb(216,216,216)'}
                  returnKeyType='done'
                  autoCapitalize='none'
                  selectionColor='#3490dc'
                  multiline={true}
                  blurOnSubmit={true}
                />
              </View>  
          </View>
        </KeyboardAvoidingView>
      </ScrollView>
      )
  }
}



const styles = StyleSheet.create({
    container: {
        //flex: 1,
        backgroundColor: 'rgb(0,0,0)'
    },
    textInput: {
        color: 'rgb(255,255,255)',
        fontSize: 18,
    },
    textBox: {
      borderColor: '#242F39',
      borderWidth: 2,
      borderRadius: 2, 
      padding: 10,
      paddingLeft: 16,
      marginTop: 10,
      backgroundColor: '#0A151F'
    }
})

【问题讨论】:

    标签: android ios react-native


    【解决方案1】:

    我最终将 ScrollView 放在 KeyboardAvoidingView 中,然后还使用填充而不是位置来进行行为。然后,我还添加了键盘侦听器,以根据键盘的大小修改视图下方的填充。

    import React from 'react'
    import { StyleSheet, View, Text, TextInput, ScrollView, KeyboardAvoidingView, Platform, NativeModules, Dimensions, SafeAreaView, Keyboard, Animated } from 'react-native'
    import Message from './message'
    
    const { StatusBarManager } = NativeModules
    
    const screen = Dimensions.get('window')
    
    
    export default class Messages extends React.Component {
      static navigationOptions = ({ navigation }) => ({
        headerTitle: 'Messages',
        headerStyle: {
          backgroundColor: 'rgb(0,0,0)',
        },
        headerTitleStyle: {
          fontSize: 20,
          color: 'rgb(255,255,255)'
        },
        headerTintColor: 'rgb(0,122,255)',
      })
    
      state = {
        messages: [],
        keyboardPadding: new Animated.Value(0)
      }
    
      componentDidMount = () => {
        Platform.OS == 'ios' ? StatusBarManager.getHeight((statusBarFrameData) => {
          this.setState({statusBarHeight: statusBarFrameData.height})
        }) : null 
        this.keyboardWillShowListener = Keyboard.addListener('keyboardWillShow', this.keyboardWillShow)
        this.keyboardWillHideListener = Keyboard.addListener('keyboardWillHide', this.keyboardWillHide)
      }
    
      componentWillUnmount = () => {
        this.keyboardWillShowListener.remove()
        this.keyboardWillHideListener.remove()
      }
    
      keyboardWillShow = (e) => {
        Animated.timing(this.state.keyboardPadding, { toValue: 1, duration: 0}).start()
      }
    
      keyboardWillHide = () => {
        Animated.timing(this.state.keyboardPadding, { toValue: 0, duration: 0 }).start()
      }
    
      scrollStyles = (keyboardPadding) => {
        return { paddingBottom: keyboardPadding }
      }
    
      renderMessages = (messages) => {
        return messages.map((data, i) => <Message data={data} key={i}/>)
      } 
    
      addMessage = (message) => {
        let messageObj = {
          message: message,
          userId: 2,
          userName: 'Sean'
        }
        this.setState({messages: [...this.state.messages, messageObj]})
      }
    
      render() {
        return (
          <SafeAreaView style={styles.container}>
              <KeyboardAvoidingView 
                style={styles.keyboardContainer}
                behavior={Platform.OS == 'ios' ? 'padding' : null}
                keyboardVerticalOffset={this.state.statusBarHeight + 44}
              >
                <ScrollView 
                  ref={ref => this.scrollView = ref}
                  onContentSizeChange={(contentWidth, contentHeight)=> {this.scrollView.scrollToEnd({animated: true})}}
                >
                  <Animated.View style={this.scrollStyles(this.state.keyboardPadding)}>
                    {this.renderMessages(this.state.messages)}
                  </Animated.View>
                </ScrollView>
                <View style={styles.textBox}>
                  <TextInput 
                    style={styles.textInput}
                    placeholder='Reply...'
                    placeholderTextColor={'rgb(216,216,216)'}
                    returnKeyType='done'
                    autoCapitalize='none'
                    selectionColor='#3490dc'
                    multiline={true}
                    blurOnSubmit={true}
                    onSubmitEditing={(e)=> this.addMessage(e.nativeEvent.text)}
                  />
                </View>  
              </KeyboardAvoidingView>  
          </SafeAreaView>
          )
      }
    }
    
    
    
    const styles = StyleSheet.create({
        container: {
          flex: 1,
          backgroundColor: 'rgb(0,0,0)'
        },
        keyboardContainer: {
          flex: 1,
          backgroundColor: 'rgb(0,0,0)'
        },
        textInput: {
          color: 'rgb(255,255,255)',
          fontSize: 18,
        },
        textBox: {
          borderColor: '#242F39',
          borderWidth: 1,
          borderRadius: 2, 
          padding: 10,
          paddingLeft: 16,
          backgroundColor: '#0A151F',
        },
    })
    

    【讨论】:

      【解决方案2】:

      试试这个:

      const screen = Dimensions.get('window');
      
      <KeyboardAvoidingView
         behavior={Platform.OS === "ios" ? "height" : null}
         keyboardVerticalOffset={Platform.OS === 'ios' ? screen.height * 0.25 : screen.height * 0.5}
         style={{ flex: 1 }}
      >
      

      此外,如果您在键盘动画方面遇到问题(我对此有很多问题)。您可以像这样在此处删除它们:

      node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvodingView
      

      取消注释这部分

         if (duration && easing) {
            LayoutAnimation.configureNext({
              // We have to pass the duration equal to minimal accepted duration defined here: RCTLayoutAnimation.m
              duration: duration > 10 ? duration : 10,
              update: {
                duration: duration > 10 ? duration : 10,
                type: LayoutAnimation.Types[easing] || 'keyboard',
              },
            });
          }
      

      【讨论】:

      猜你喜欢
      • 2019-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-01
      • 2020-03-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多