制作多行,使用React-Native扩展TextInput

时间:2015-07-17 11:50:28

标签: ios ios8 react-native

我正在开发一个本机应用程序,并且需要一个TextInput,其功能与iOS上“messages”应用程序中的textview类似 - 它应该从一行开始,然后优雅地扩展到更多行,直到某些限制(如5行文本)然后根据需要开始滚动到最新行。

看一下SlackTextViewController但是a)好像有很多我不想要的东西和b)我想尝试在React中保留尽可能多的代码(并且Objective-C / swift)尽可能。

编辑:只是想强调我更喜欢REACT(JAVASCRIPT)代码,如上所述,而不是Objective-C或Swift。

7 个答案:

答案 0 :(得分:19)

今天我尝试了两种不同的方法。两者都不是最好的,但我想我会记录我的努力,以防它们有用。他们肯定都有你想要的效果,虽然有时会延迟所有异步通信。

1)屏幕外文字高度

所以在TextInput下,我添加了一个带有相同字体和填充等的常规Text字段。我在输入上注册了onChange侦听器并调用了setState({text: event.nativeEvent.text})。文本归档从州获得了它的价值。两人都有onLayout听众。基本上,目标是从(不受限制的)Text获取TextInput的高度。然后我隐藏了屏幕外的文字方式

https://gist.github.com/bleonard/f7d748e89ad2a485ec34

2)原生模块

真的,我只需要真实 UITextView中内容的高度。所以我在RCTUIManager中添加了一个类别,因为有几种方法已经有用了。我摆脱了隐藏的文本视图。所以onChange,我要求高度并通过状态以相同的方式使用它。

https://gist.github.com/bleonard/6770fbfe0394a34c864b

3)Github PR

我真的希望这个公关被接受。它看起来自动做这样的事情。

https://github.com/facebook/react-native/pull/1229

答案 1 :(得分:11)

如果文本量超出可用空间,则将multiline={true}添加到TextInput将允许滚动。然后,您可以通过从onChange prop访问事件的nativeEvent.contentSize.height来更改TextInput的高度。

class Comment extends Component {
   state = {
      text: '',
      height: 25
   }

   onTextChange(event) {
     const { contentSize, text } = event.nativeEvent;

     this.setState({
        text: text,
        height: contentSize.height > 100 ? 100 : contentSize.height
     }); 
   }

   render() {
      return (
         <TextInput
            multiline
            style={{ height: this.state.height }}
            onChange={this.onTextChange.bind(this)}
            value={this.state.text}
         />
      );
   }
}

答案 2 :(得分:1)

实施UITextView的委托方法textViewDidChange并使用rect

- (void)textViewDidChange:(UITextView *)textView {
  CGSize constraintSize = CGSizeMake(textView.frame.size.width, MAXFLOAT);
  CGRect textRect = [textView.text boundingRectWithSize:constraintSize
                                               options:NSStringDrawingUsesLineFragmentOrigin
                                            attributes:@{NSFontAttributeName:textView.font}
                                               context:nil];
  NSLog(@"Frame:%@", NSStringFromCGRect(textRect));
  CGRect newRect = textView.frame;
  newRect.size.height = textRect.size.height;
  textView.frame = newRect;
}

答案 3 :(得分:1)

截至10月17日,Wix有一个很好的组件可以做到这一点:

https://github.com/wix/react-native-autogrow-textinput

用法非常简单:

<AutoGrowingTextInput
  style={styles.textInput}
  placeholder="Enter text"
  value={this.state.text}
  onChangeText={this._handleChangeText}
/>

还有一些额外的道具,例如minHeightmaxHeight

我在RN 0.47.2

上使用它

答案 4 :(得分:0)

另一种解决方案是检查{Subdomain !>> [.][0-9] "."}+符号并设置'\n'属性。 为我工作。

numberOfLines

答案 5 :(得分:0)

@Groovietunes几乎所有内容都正确无误,但截止到26-06-19为止,他的最初回答有所改变。

例如,文本输入中的onChange道具不再返回contentSize对象,因此event.nativeEvent.contentSize将返回undefined

此问题的解决方法是使用onContentSizeChange道具。但是有一个陷阱。 onContentSizeChange仅在组件安装时运行一次,因此无法随着变化而动态获得高度。

要解决此问题,我们需要确保在道具层次结构中的value之后设置onContentSizeChange道具,以便随着textinput的增长而不断获得内容尺寸。

最后,我有一个看起来像这样的组件

<TextInput
        placeholder={this.props.placeholder}
        autoFocus={this.props.autoFocus}
        style={[
          styles.inputFlat,
          { height: this.state.height > 40 ? this.state.height : 40 }
        ]}
        ref="inputFlat"
        onFocus={() => {
          this.toggleInput();
          this.toggleButton();
        }}
        multiline={this.props.multiline}
        onBlur={() => {
          this.toggleInput();
          this.toggleButton();
        }}
        onChangeText={this.props.onChangeText} 
        onContentSizeChange={event => {
          const { contentSize } = event.nativeEvent;
          this.setState({
            height: contentSize.height
          });
        }}
        value={this.state.value}
      />

如果由于某种原因在查看此答案时似乎已损坏,请参阅this文档以获取任何更新

答案 6 :(得分:0)

对于任何想要简单解决方案的人,使用新版本的 RN,目前使用 0.63.4, 团队将 autoGrow 添加到 TextInput(如果它是多行的),就是这种情况。

不要对组件或父视图/视图使用 height(StyeSheet 属性)

改用minHeightma​​xHeight,如果启用了多行,TextInput 将增长直到达到ma​​xHeight,然后可以滚动。

不需要维护任何计算和内部状态。

如果您需要广泛扩展,同样适用于 minWidthma​​xWidth