diff --git a/Examples/UIExplorer/TextInputExample.ios.js b/Examples/UIExplorer/TextInputExample.ios.js
index d51a95e33bb5fd..c4f0bdafd2b29c 100644
--- a/Examples/UIExplorer/TextInputExample.ios.js
+++ b/Examples/UIExplorer/TextInputExample.ios.js
@@ -149,6 +149,15 @@ var styles = StyleSheet.create({
right: 5,
backgroundColor: 'red',
},
+ multilineAutoGrow: {
+ borderWidth: 0.5,
+ borderColor: '#0f0f0f',
+ flex: 1,
+ fontSize: 13,
+ height: 30,
+ padding: 4,
+ marginBottom: 4,
+ },
eventLabel: {
margin: 3,
fontSize: 12,
@@ -434,6 +443,13 @@ exports.examples = [
style={styles.multiline}>
+
+
);
}
diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index f96c1852fca60a..b19886bf2a3fce 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -34,6 +34,8 @@ var onlyMultiline = {
onSelectionChange: true, // not supported in Open Source yet
onTextInput: true, // not supported in Open Source yet
children: true,
+ autoGrow: true,
+ maxHeight: true,
};
var notMultiline = {
@@ -100,6 +102,16 @@ var TextInput = React.createClass({
* If false, disables auto-correct. The default value is true.
*/
autoCorrect: PropTypes.bool,
+ /**
+ * If true, and the input is multiline, the input's height will grow automatically. The default value is false.
+ * @platorm ios
+ */
+ autoGrow: PropTypes.bool,
+ /**
+ * The maximum height the input should grow to when autoGrow is true.
+ * @platorm ios
+ */
+ maxHeight: PropTypes.number,
/**
* If true, focuses the input on componentDidMount.
* The default value is false.
diff --git a/Libraries/Text/RCTTextView.h b/Libraries/Text/RCTTextView.h
index c5012ec0917411..4df27d37bf6d58 100644
--- a/Libraries/Text/RCTTextView.h
+++ b/Libraries/Text/RCTTextView.h
@@ -10,6 +10,7 @@
#import
#import "RCTView.h"
+#import "RCTUIManager.h"
#import "UIView+React.h"
@class RCTEventDispatcher;
@@ -17,6 +18,8 @@
@interface RCTTextView : RCTView
@property (nonatomic, assign) BOOL autoCorrect;
+@property (nonatomic, assign) BOOL autoGrow;
+@property (nonatomic, assign) float maxHeight;
@property (nonatomic, assign) BOOL clearTextOnFocus;
@property (nonatomic, assign) BOOL selectTextOnFocus;
@property (nonatomic, assign) UIEdgeInsets contentInset;
@@ -28,6 +31,6 @@
@property (nonatomic, assign) NSInteger mostRecentEventCount;
@property (nonatomic, strong) NSNumber *maxLength;
-- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
@end
diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m
index d21360ed26c1be..74435ffed9d8b1 100644
--- a/Libraries/Text/RCTTextView.m
+++ b/Libraries/Text/RCTTextView.m
@@ -12,25 +12,32 @@
#import "RCTConvert.h"
#import "RCTEventDispatcher.h"
#import "RCTUtils.h"
+#import "RCTUIManager.h"
#import "UIView+React.h"
@implementation RCTTextView
{
+ RCTBridge *_bridge;
RCTEventDispatcher *_eventDispatcher;
BOOL _jsRequestingFirstResponder;
+ BOOL _autoGrow;
+ float _origHeight;
+ float _maxHeight;
NSString *_placeholder;
UITextView *_placeholderView;
UITextView *_textView;
NSInteger _nativeEventCount;
}
-- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
+- (instancetype)initWithBridge:(RCTBridge *)bridge
{
- RCTAssertParam(eventDispatcher);
+ RCTAssertParam(bridge);
if ((self = [super initWithFrame:CGRectZero])) {
+ _bridge = bridge;
+ _autoGrow = false;
_contentInset = UIEdgeInsetsZero;
- _eventDispatcher = eventDispatcher;
+ _eventDispatcher = _bridge.eventDispatcher;
_placeholderTextColor = [self defaultPlaceholderTextColor];
_textView = [[UITextView alloc] initWithFrame:self.bounds];
@@ -67,6 +74,10 @@ - (void)updateFrames
_textView.textContainerInset = adjustedTextContainerInset;
_placeholderView.textContainerInset = adjustedTextContainerInset;
+
+ if (! _origHeight) {
+ _origHeight = self.frame.size.height;
+ }
}
- (void)updatePlaceholder
@@ -89,6 +100,40 @@ - (void)updatePlaceholder
}
}
+- (void)updateTextViewFrame
+{
+ if (self.superview == nil) {
+ return;
+ }
+
+ if (_autoGrow) {
+ if (CGRectIsEmpty(self.frame)) {
+ return;
+ }
+
+ float currentHeight = _textView.frame.size.height;
+ float newHeight;
+
+ [_textView sizeToFit];
+
+ if (_textView.frame.size.height >= _origHeight) {
+ newHeight = _textView.frame.size.height;
+ } else {
+ newHeight = _origHeight;
+ }
+
+ if (_maxHeight > _origHeight) {
+ newHeight = fminf(newHeight, _maxHeight);
+ }
+
+ if (newHeight != currentHeight) {
+ CGRect newFrame = CGRectMake(0, 0, self.frame.size.width, newHeight);
+ [_bridge.uiManager setFrame:newFrame
+ forView:self];
+ }
+ }
+}
+
- (UIFont *)font
{
return _textView.font;
@@ -98,6 +143,7 @@ - (void)setFont:(UIFont *)font
{
_textView.font = font;
[self updatePlaceholder];
+ [self updateTextViewFrame];
}
- (UIColor *)textColor
@@ -169,6 +215,7 @@ - (void)setText:(NSString *)text
UITextRange *selection = _textView.selectedTextRange;
_textView.text = text;
[self _setPlaceholderVisibility];
+ [self updateTextViewFrame];
_textView.selectedTextRange = selection; // maintain cursor position/selection - this is robust to out of bounds
} else if (eventLag > RCTTextUpdateLagWarningThreshold) {
RCTLogWarn(@"Native TextInput(%@) is %zd events ahead of JS - try to make your JS faster.", self.text, eventLag);
@@ -194,6 +241,16 @@ - (BOOL)autoCorrect
return _textView.autocorrectionType == UITextAutocorrectionTypeYes;
}
+- (void)setAutoGrow:(BOOL)autoGrow
+{
+ _autoGrow = autoGrow;
+}
+
+- (void)setMaxHeight:(float)maxHeight
+{
+ _maxHeight = maxHeight;
+}
+
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
if (_selectTextOnFocus) {
@@ -220,6 +277,8 @@ - (void)textViewDidBeginEditing:(UITextView *)textView
- (void)textViewDidChange:(UITextView *)textView
{
[self _setPlaceholderVisibility];
+ [self updateTextViewFrame];
+
_nativeEventCount++;
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeChange
reactTag:self.reactTag
diff --git a/Libraries/Text/RCTTextViewManager.m b/Libraries/Text/RCTTextViewManager.m
index f47a106bdf49a9..7b4851ce9b6ac7 100644
--- a/Libraries/Text/RCTTextViewManager.m
+++ b/Libraries/Text/RCTTextViewManager.m
@@ -21,10 +21,12 @@ @implementation RCTTextViewManager
- (UIView *)view
{
- return [[RCTTextView alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
+ return [[RCTTextView alloc] initWithBridge:self.bridge];
}
RCT_EXPORT_VIEW_PROPERTY(autoCorrect, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(autoGrow, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(maxHeight, float)
RCT_REMAP_VIEW_PROPERTY(editable, textView.editable, BOOL)
RCT_EXPORT_VIEW_PROPERTY(placeholder, NSString)
RCT_EXPORT_VIEW_PROPERTY(placeholderTextColor, UIColor)