mirror of
https://github.com/status-im/react-native.git
synced 2025-01-27 01:40:08 +00:00
Added support for auto-resizing text fields
Summary: public This diff adds support for auto-resizing multiline text fields. This has been a long-requested feature, with several native solutions having been proposed (see https://github.com/facebook/react-native/pull/1229 and D2846915). Rather than making this a feature of the native component, this diff simply exposes some extra information in the `onChange` event that makes it easy to implement this in pure JS code. I think this is preferable, since it's simpler, works cross-platform, and avoids any controversy about what the API should look like, or how the props should be named. It also makes it easier to implement custom min/max-height logic. Reviewed By: sahrens Differential Revision: D2849889 fb-gh-sync-id: d9ddf4ba4037d388dac0558aa467d958300aa691
This commit is contained in:
parent
0893d07db1
commit
481f560f64
@ -72,6 +72,29 @@ var TextEventsExample = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
class AutoExpandingTextInput extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {text: '', height: 0};
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<TextInput
|
||||
{...this.props}
|
||||
multiline={true}
|
||||
onChange={(event) => {
|
||||
this.setState({
|
||||
text: event.nativeEvent.text,
|
||||
height: event.nativeEvent.contentSize.height,
|
||||
});
|
||||
}}
|
||||
style={[styles.default, {height: Math.max(35, this.state.height)}]}
|
||||
value={this.state.text}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RewriteExample extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -385,6 +408,20 @@ exports.examples = [
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Auto-expanding',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<AutoExpandingTextInput
|
||||
placeholder="height increases with content"
|
||||
enablesReturnKeyAutomatically={true}
|
||||
returnKeyType="done"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Attributed text',
|
||||
render: function() {
|
||||
|
@ -96,6 +96,29 @@ var TextEventsExample = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
class AutoExpandingTextInput extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {text: '', height: 0};
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<TextInput
|
||||
{...this.props}
|
||||
multiline={true}
|
||||
onChange={(event) => {
|
||||
this.setState({
|
||||
text: event.nativeEvent.text,
|
||||
height: event.nativeEvent.contentSize.height,
|
||||
});
|
||||
}}
|
||||
style={[styles.default, {height: Math.max(35, this.state.height)}]}
|
||||
value={this.state.text}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RewriteExample extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -630,6 +653,20 @@ exports.examples = [
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Auto-expanding',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<AutoExpandingTextInput
|
||||
placeholder="height increases with content"
|
||||
enablesReturnKeyAutomatically={true}
|
||||
returnKeyType="done"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Attributed text',
|
||||
render: function() {
|
||||
|
@ -61,6 +61,8 @@
|
||||
NSMutableArray<UIView *> *_subviews;
|
||||
BOOL _blockTextShouldChange;
|
||||
UITextRange *_previousSelectionRange;
|
||||
NSUInteger _previousTextLength;
|
||||
CGFloat _previousContentHeight;
|
||||
UIScrollView *_scrollView;
|
||||
}
|
||||
|
||||
@ -437,12 +439,36 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
[self updateContentSize];
|
||||
[self _setPlaceholderVisibility];
|
||||
_nativeEventCount++;
|
||||
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeChange
|
||||
reactTag:self.reactTag
|
||||
text:textView.text
|
||||
key:nil
|
||||
eventCount:_nativeEventCount];
|
||||
|
||||
if (!self.reactTag) {
|
||||
return;
|
||||
}
|
||||
|
||||
// When the context size increases, iOS updates the contentSize twice; once
|
||||
// with a lower height, then again with the correct height. To prevent a
|
||||
// spurious event from being sent, we track the previous, and only send the
|
||||
// update event if it matches our expectation that greater text length
|
||||
// should result in increased height. This assumption is, of course, not
|
||||
// necessarily true because shorter text might include more linebreaks, but
|
||||
// in practice this works well enough.
|
||||
NSUInteger textLength = textView.text.length;
|
||||
CGFloat contentHeight = textView.contentSize.height;
|
||||
if (textLength >= _previousTextLength) {
|
||||
contentHeight = MAX(contentHeight, _previousContentHeight);
|
||||
}
|
||||
_previousTextLength = textLength;
|
||||
_previousContentHeight = contentHeight;
|
||||
|
||||
NSDictionary *event = @{
|
||||
@"text": self.text,
|
||||
@"contentSize": @{
|
||||
@"height": @(contentHeight),
|
||||
@"width": @(textView.contentSize.width)
|
||||
},
|
||||
@"target": self.reactTag,
|
||||
@"eventCount": @(_nativeEventCount),
|
||||
};
|
||||
[_eventDispatcher sendInputEventWithName:@"change" body:event];
|
||||
}
|
||||
|
||||
- (void)textViewDidEndEditing:(UITextView *)textView
|
||||
|
Loading…
x
Reference in New Issue
Block a user