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.
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.
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}
/>
);
}
}
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;
}
À 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
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,
};