création d'une multiligne, expansion de TextInput avec React-Native

Je travaille sur une application react-native et j'ai besoin d'un TextInput qui a des fonctionnalités similaires à textview dans l'application "messages" sur iOS-il devrait commencer comme une ligne, puis s'étendre gracieusement à plus de lignes jusqu'à une certaine limite (comme 5 lignes de texte), puis commencer à faire défiler jusqu'à la dernière ligne

A jeté un oeil au SlackTextViewController mais a) semble avoir beaucoup de choses que je ne veux pas et b) j'aimerais essayer de garder autant de code dans React (et Hors objective-C/swift) que possible.

Edit: je veux juste souligner que je préférerais le code REACT (JAVASCRIPT), comme indiqué ci-dessus, plutôt que Objective-C ou Swift.

24
demandé sur Aaron Yodaiken 2015-07-17 14:50:28

5 réponses

J'ai essayé deux façons différentes de le faire aujourd'hui. Ni sont les meilleurs, mais je pensais que je voudrais enregistrer mes efforts au cas où ils sont utiles. Ils ont tous deux certainement eu l'effet que vous recherchez, bien que parfois retardé avec toute la communication asynchrone.

1) Hauteur du texte hors écran

Donc, juste sous le TextInput, j'ai ajouté un champ de texte régulier avec la même police et le même remplissage et autres. J'ai enregistré l'écouteur onChange sur l'entrée et appelé setState({text: event.nativeEvent.text}). Le texte déposé a obtenu sa valeur de la état. Les deux avaient onLayout auditeurs. Fondamentalement, le but était d'obtenir la hauteur pour le TextInput à partir du texte (sans restriction). Ensuite, j'ai caché le texte hors écran

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

2) Module Natif

Vraiment, j'avais juste besoin de la hauteur du contenu dans lereal UITextView. J'ai donc ajouté une catégorie à RCTUIManager car il existe déjà plusieurs méthodes qui sont utiles. Je me suis débarrassé de la vue texte cachée. Si onChange, Je demande la hauteur et l'utilise de la même manière via l'état.

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

3) GitHub PR

Ce que j'espère vraiment, c'est que ce PR soit accepté. Il semble faire quelque chose comme ça automatiquement.

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

19
répondu bleonard 2015-08-01 06:43:41

L'ajout de multiline={true} à un TextInput permet le défilement si la quantité de texte dépasse l'espace disponible. Vous pouvez ensuite modifier la hauteur du TextInput en accédant à nativeEvent.contentSize.hauteur de l'événement à partir de l'accessoire onChange.

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}
         />
      );
   }
}
11
répondu Groovietunes 2016-11-06 08:27:39

Implémentez la méthode déléguée de UITextView textViewDidChange et jouez avec le 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;
}
1
répondu Inder Kumar Rathore 2015-07-28 11:45:41

À partir du 17 Octobre, Il y a un bon composant de Wix pour faire ceci:

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

L'utilisation peut être très simple:

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

Et il y a quelques accessoires supplémentaires comme minHeight et maxHeight par exemple.

Je l'utilise sur RN 0.47.2

1
répondu zubko 2017-10-03 21:39:22

Une autre solution consiste à vérifier les symboles '\n' et à définir la propriété numberOfLines. Fonctionne pour moi.

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,
};
0
répondu Yuri Tinyukov 2018-06-21 17:18:44