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

Posted

技术标签:

【中文标题】使用 React-Native 制作多行扩展 TextInput【英文标题】:making a multiline, expanding TextInput with React-Native 【发布时间】:2015-07-17 11:50:28 【问题描述】:

我正在开发一个 react-native 应用程序,需要一个 TextInput,它与 ios 上的“消息”应用程序中的 textview 具有相似的功能——它应该从一行开始,然后优雅地扩展到更多行,直到达到某个限制(如 5 行文本),然后根据需要开始滚动到最新行。

查看了SlackTextViewController,但 a) 似乎它有很多我不想要的东西,并且 b) 我想尝试在 React 中保留尽可能多的代码(并且出于目标 - C/swift) 尽可能。

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

【问题讨论】:

看看这个库,它已经有一段时间没有更新了,但它运行得很好。 github.com/HansPinckaers/GrowingTextView 【参考方案1】:

我今天尝试了两种不同的方法。两者都不是最好的,但我想我会记录我的努力以防万一。他们都肯定有你正在寻找的效果,尽管有时会因所有异步通信而延迟。

1) 离屏文字高度

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

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

2) 原生模块

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

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

3) Github 公关

我真正希望的是这个 PR 被接受。它看起来会自动执行类似的操作。

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

【讨论】:

你能把这些要点公开而不是秘密吗?在您的 Gist 个人资料中找不到它们 :) 更新:已添加对自动调整文本字段大小的支持github.com/facebook/react-native/commit/…【参考方案2】:

如果文本量超过可用空间,将multiline=true 添加到 TextInput 将允许滚动。然后,您可以通过从 onChange 属性访问事件的 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
         />
      );
   

【讨论】:

【参考方案3】:

截至 17 年 10 月,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 上使用它

【讨论】:

今天仍在使用 "react-native": "0.62.2", "react-native-autogrow-input": "0.2.1", 【参考方案4】:

实现UITextView的委托方法textViewDidChange并玩转矩形

- (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;

【讨论】:

【参考方案5】:

@Groovietunes 几乎所有内容都正确,但截至 2019 年 6 月 26 日,情况与他最初的回答有所不同。

一方面,textinputs 上的 onChange 属性不再返回 contentSize 对象,因此 event.nativeEvent.contentSize 将返回 undefined

解决此问题的方法是使用 onContentSizeChange 属性。但是有一个问题。 onContentSizeChange 仅在组件安装时运行一次,因此无法在组件更改时动态获取高度。

要解决这个问题,我们需要确保 value 在 props 层次结构中设置在 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】:

另一种解决方案是检查'\n' 符号并设置numberOfLines 属性。 对我有用。

import React,  Component  from 'react';
import PropTypes from 'prop-types';
import TextInput from 'react-native';

export default class TextInputAutogrow extends Component 

    constructor(props) 

        super(props);

        this._ref = null;

        this.bindRef = this.bindRef.bind(this);
        this.onChangeText = this.onChangeText.bind(this);

        this.state = 
            numberOfLines: this.getNumberOfLines()
        ;
    

    bindRef(c) 

        this._ref = c;

        this.props.innerRef && this.props.innerRef(c);
    

    getText() 

        return typeof this.props.value === 'string' ?
            this.props.value :
            (
                typeof this.props.defaultValue === 'string' ?
                    this.props.defaultValue :
                    ''
            );
    

    getNumberOfLines(value) 

        if (value === undefined) 

            value = this.getText();
        

        return Math.max(this.props.numberOfLines, value.split('\n').length - 1) + 1;
    

    onChangeText(value) 

        this.setState(numberOfLines: this.getNumberOfLines(value))
    

    render() 

        return (
            <TextInput
                ...this.props
                ref=this.bindRef
                numberOfLines=this.state.numberOfLines
                onChangeText=this.onChangeText
            />
        )
    


TextInputAutogrow.propTypes = 
    ...TextInput.propTypes,
    innerRef: PropTypes.func,
;

TextInputAutogrow.defaultProps = 
    numberOfLines: 4,
;

【讨论】:

【参考方案7】:

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

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

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

无需维护任何计算或内部状态。

minWidthma​​xWidth同样适用,如果您需要大幅扩展。

【讨论】:

以上是关于使用 React-Native 制作多行扩展 TextInput的主要内容,如果未能解决你的问题,请参考以下文章

如何在react-native中的多行文本中断后确定“更多”链接/按钮的位置

如何通过扩展 mx.containers.Panel 在 flex 3 中创建具有多行标题的面板?

如何制作需要特定导入的混合包 React/React-Native

如何使用 React-native 根据距离制作过滤器

在 React-Native 中制作指南针

使用 axios 在 react-native 中使用 POST 方法获取 API 数据