簡體   English   中英

React Native - 如何使 ScrollView 中的 KeyboardAvoidingView 適用於所有設備?

[英]React Native - How to make KeyboardAvoidingView inside a ScrollView work for all devices?

在此處輸入圖像描述

我正在構建一個反應原生的聊天 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'
    }
})

我最終將 ScrollView 放在 KeyboardAvoidingView 中,然后還使用填充而不是 position 來進行行為。 然后,我還添加了鍵盤偵聽器,以根據鍵盤的大小修改視圖下方的填充。

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',
    },
})

嘗試這個:

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',
        },
      });
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM