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:
Nick Lockwood
2016-01-25 05:45:44 -08:00
committed by facebook-github-bot-5
parent 0893d07db1
commit 481f560f64
3 changed files with 105 additions and 5 deletions

View File

@@ -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