【问题标题】:How to prevent auto-grow text input container from growing behind keyboard in react-native如何防止自动增长文本输入容器在 react-native 中在键盘后面增长
【发布时间】:2020-08-20 18:43:46
【问题描述】:

目标:创建一个文本输入字段,该字段会随着输入行的扩展而响应扩展,直到某个点,就像大多数消息传递应用程序一样。

问题:当输入扩展超过 3 或 4 行时,输入容器的顶部不是向上扩展,而是根据内容大小扩展,但容器被重新定位在键盘/键盘单词后面建议,它将按钮重新定位在左侧(输入容器的一部分)以及 <TextInput> 本身。

下图显示了我希望填充位于底部的方式。 “下部容器”体现了按钮和输入字段。灰白色是键盘建议的顶部(iOS)

下图显示了不良行为。您可以看到输入的底部边框,以及按钮开始消失在建议框/键盘后面。如果输入继续扩大,底部边框和按钮将逐渐变得不那么明显。

这是整个屏幕组件:

render () {
    return (
        <KeyboardAvoidingView
            style={{ flex: 1, backgroundColor: Colors.PRIMARY_OFF_WHITE,
            }}
            behavior={Platform.OS === 'ios' ? 'position' : null}
            keyboardVerticalOffset={Platform.OS === 'ios' ?hp("11%") : 0}
        >

        /* Upper Container */
        <View style={{ justifyContent: 'flex-start', height: height*0.8, paddingBottom: 10 }}>
            <FlatList
                data={this.props.messages}
                ref={'list'}
                onContentSizeChange={() => this.refs.list.scrollToEnd()}
                keyExtractor={(item) => {
                    return (
                        item.toString() +
                        new Date().getTime().toString() +
                        Math.floor(Math.random() * Math.floor(new Date().getTime())).toString()
                    );
                }}
                renderItem={({ item, index }) => {
                    return (
                        <Components.ChatMessage
                            isSender={item.sender == this.props.uid ? true : false}
                            message={item.content.data}
                            read={item.read}
                            time={item.time}
                            onPress={() =>
                                this.props.readMsg(
                                    {
                                        id: this.props.uid,
                                        role: this.props.role,
                                        convoId: this.state.ownerConvoId
                                    },
                                    item.docId,
                                    this.props.navigation.state.params.uid
                                )}
                         />
                      );
                  }}                    
                />
                </View>

            /* Lower Container */
                <View
                    style={{
                        height: this.state.height+20,
                        flexDirection: 'row',
                        alignItems: 'center',
                        justifyContent:"space-around",
                        paddingVertical: 10
                    }}
                >
                    <Components.OptionFan
                        options={[
                            {
                                icon: require('../assets/img/white-voice.png'),
                                onPress: () => {
                                  this.props.navigation.navigate('Schedule', {
                                        receiver: this.conversants.receiver,
                                        sender: this.conversants.sender,
                                        type: 'Voice'
                                    });
                                },
                                key: 1
                             },
                             {
                                icon: require('../assets/img/white-video.png'),
                                onPress: () => {
                                    this.props.navigation.navigate('Schedule', {
                                        receiver: this.conversants.receiver,
                                        sender: this.conversants.sender,
                                        type: 'Video'
                                    });
                                },
                                key: 2
                              }
                          ]}
                      />


                        <TextInput
                            multiline={true}
                            textAlignVertical={'center'}
                            onChangeText={(text) => this.setState({ text })}
                            onFocus={() => this.refs.list.scrollToEnd()}
                            onContentSizeChange={(event) =>
                                this.setState({
                                    height:
                                        event.nativeEvent.contentSize.height <= 40
                                            ? 40
                                            : event.nativeEvent.contentSize.height
                                })}
                            style={{
                                height: Math.max(40, this.state.height),
                                width: wp('80%'),
                                borderWidth: 1,
                                alignSelf: this.state.height > 40 ? "flex-end":null,
                                borderColor: Colors.PRIMARY_GREEN,
                                borderRadius: 18,
                                paddingLeft: 15,
                                paddingTop: 10,
                                paddingRight: 15
                            }}
                            ref={'input'}
                            blurOnSubmit={true}
                            returnKeyType={'send'}
                            placeholder={'Write a message...'}
                            onSubmitEditing={() => {
                                if (this.props.role == 'Influencer') {
                                    this.send();
                                    this.refs.input.clear();
                                } else {

                                    this.setState({ visible: true });
                                }
                            }}
                        />
                    </View>
            </KeyboardAvoidingView>
        );
    }

我怎样才能实现一个在底部有所需填充的保持在视图中的outgrow?

编辑:要清楚,这个问题不是关于如何制作自动增长的输入字段。上面的代码已经完成了。它关于自动增长输入字段所在的容器,以及父容器、输入字段和按钮如何在键盘/键盘建议之后增长。 目标是让文本输入始终直接显示在键盘上方,输入/按钮/容器的底部在键盘之间始终保持相同的间距,而高度仅向上扩展。

这里发布的问题类似:In React Native, How to have multiple multiline textinputs that don't hide behind the keyboard in one scrollable form?

【问题讨论】:

标签: reactjs react-native react-native-android react-native-ios


【解决方案1】:

您可以将父容器设置为 '100%' 高度并调整上部内容的大小,以便输入容器始终向上增长。

一个简单的实现如下。 textInputHeight 取自状态,并在 TextInput 调整大小时设置。

  return (
    <KeyboardAvoidingView
      style={{height: '100%'}}
      behavior={Platform.OS === 'ios' ? 'position' : undefined}
      keyboardVerticalOffset={100}>
      <ScrollView
        style={{
          backgroundColor: '#777',
          height: height - (80 + textInputHeight),
        }}>
        <View style={{height: 1000}} />
      </ScrollView>
      <TextInput
        multiline={true}
        onLayout={(event) => {
          if (textInputHeight === 0) {
            setTextInputHeight(event.nativeEvent.layout.height);
          }
        }}
        onContentSizeChange={(event) => {
          setTextInputHeight(event.nativeEvent.contentSize.height);
        }}
      />
    </KeyboardAvoidingView>
  );

【讨论】:

  • 您的解决方案肯定很有帮助,获得了赏金。但我的问题是滚动视图高度中的硬编码80。你只是把输入的初始高度加倍了吗?因为我遇到的问题是 1)我需要一些数字来从上部容器中减去更多高度,以及 2)下部容器的位置因设备而异,以及是否为 android/iOS。有什么建议吗?
  • 80 有点随意以避免我的 iOS 模拟器底部的导航栏,您应该能够通过使用诸如 npmjs.com/package/react-native-static-safe-area-insets 之类的库来动态获取它。它不依赖于实际的文本输入大小。
  • 我能用维度和原生模块的api搞清楚,谢谢兄弟
  • 能否请您解释一下,您从哪里得到textInputHeight 及其初始值?
【解决方案2】:

作为附加说明,在考虑屏幕部分的动态高度时,请始终记住考虑状态栏(显然是 iOS 和 android)以及屏幕底部令人讨厌的软 Android 导航栏,因为将 Dimension api 用于“窗口”时,未将其考虑在内。我的错误忽略了这一点。

获取状态栏和导航栏:

import {NativeModules, Platform} from 'react-native';

const { StatusBarManager } = NativeModules; // Note: StatusBar API is not good used here because of platform inconsistencies.

// Note: 'window' does not contain Android/iOS status bar or Android soft Navigation Bar
const WINDOW_HEIGHT = Dimensions.get('window').height;

// 'screen' gets full hardware dimension
const DEVICE_HEIGHT = Dimensions.get('screen').height;
const STATUS_BAR_HEIGHT = Platform.OS === 'ios' ? 20 : StatusBarManager.HEIGHT;
const ANDROID_NAV_HEIGHT = Platform.OS === 'ios' ? 0 : DEVICE_HEIGHT -  (WINDOW_HEIGHT + STATUSBAR_HEIGHT);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-02
    • 1970-01-01
    • 2021-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多