TextInput: Refined contentSize calculation

Summary: This fixes pretty bad issue when contentSize is calculated based on an intrinsic horizontal (width) limitation, not on a real/current horizontal (width) one.

Reviewed By: mmmulani

Differential Revision: D5422114

fbshipit-source-id: 0eb582aeb59d29530990d4faabf2f41baa79c058
This commit is contained in:
Valentin Shergin 2017-07-18 14:33:58 -07:00 committed by Facebook Github Bot
parent f5d9b5210e
commit 603cc48ceb
5 changed files with 46 additions and 5 deletions

View File

@ -22,6 +22,7 @@
@property (nonatomic, assign) UIEdgeInsets textContainerInset;
@property (nonatomic, strong, nullable) UIView *inputAccessoryView;
@property (nonatomic, weak, nullable) id<RCTBackedTextInputDelegate> textInputDelegate;
@property (nonatomic, readonly) CGSize contentSize;
// This protocol disallows direct access to `selectedTextRange` property because
// unwise usage of it can break the `delegate` behavior. So, we always have to

View File

@ -168,10 +168,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
- (CGSize)contentSize
{
CGSize contentSize = self.intrinsicContentSize;
UIEdgeInsets compoundInsets = self.reactCompoundInsets;
contentSize.width -= compoundInsets.left + compoundInsets.right;
contentSize.height -= compoundInsets.top + compoundInsets.bottom;
CGSize contentSize = self.backedTextInputView.contentSize;
UIEdgeInsets reactPaddingInsets = self.reactPaddingInsets;
contentSize.width -= reactPaddingInsets.left + reactPaddingInsets.right;
contentSize.height -= reactPaddingInsets.top + reactPaddingInsets.bottom;
// Returning value does NOT include border and padding insets.
return contentSize;
}

View File

@ -137,6 +137,12 @@
#pragma mark - Layout
- (CGSize)contentSize
{
// Returning size DOES contain `textContainerInset` (aka `padding`).
return self.intrinsicContentSize;
}
- (CGSize)intrinsicContentSize
{
// Note: `placeholder` defines intrinsic size for `<TextInput>`.
@ -145,11 +151,13 @@
size = CGSizeMake(RCTCeilPixelValue(size.width), RCTCeilPixelValue(size.height));
size.width += _textContainerInset.left + _textContainerInset.right;
size.height += _textContainerInset.top + _textContainerInset.bottom;
// Returning size DOES contain `textContainerInset` (aka `padding`).
return size;
}
- (CGSize)sizeThatFits:(CGSize)size
{
// All size values here contain `textContainerInset` (aka `padding`).
CGSize intrinsicSize = self.intrinsicContentSize;
return CGSizeMake(MIN(size.width, intrinsicSize.width), MIN(size.height, intrinsicSize.height));
}

View File

@ -152,6 +152,7 @@ static UIColor *defaultPlaceholderColor()
- (CGFloat)preferredMaxLayoutWidth
{
// Returning size DOES contain `textContainerInset` (aka `padding`).
return _preferredMaxLayoutWidth ?: self.placeholderSize.width;
}
@ -167,6 +168,18 @@ static UIColor *defaultPlaceholderColor()
return placeholderSize;
}
- (CGSize)contentSize
{
CGSize contentSize = super.contentSize;
CGSize placeholderSize = self.placeholderSize;
// When a text input is empty, it actually displays a placehoder.
// So, we have to consider `placeholderSize` as a minimum `contentSize`.
// Returning size DOES contain `textContainerInset` (aka `padding`).
return CGSizeMake(
MAX(contentSize.width, placeholderSize.width),
MAX(contentSize.height, placeholderSize.height));
}
- (void)layoutSubviews
{
[super layoutSubviews];
@ -179,6 +192,7 @@ static UIColor *defaultPlaceholderColor()
- (CGSize)intrinsicContentSize
{
// Returning size DOES contain `textContainerInset` (aka `padding`).
return [self sizeThatFits:CGSizeMake(self.preferredMaxLayoutWidth, INFINITY)];
}
@ -187,7 +201,7 @@ static UIColor *defaultPlaceholderColor()
// Returned fitting size depends on text size and placeholder size.
CGSize textSize = [self fixedSizeThatFits:size];
CGSize placeholderSize = self.placeholderSize;
// Returning size DOES contain `textContainerInset`.
// Returning size DOES contain `textContainerInset` (aka `padding`).
return CGSizeMake(MAX(textSize.width, placeholderSize.width), MAX(textSize.height, placeholderSize.height));
}

View File

@ -823,6 +823,24 @@ exports.examples = [
placeholder="Placeholder defines intrinsic size"
/>
</View>
<View>
<TextInput
style={{
fontSize: 16,
backgroundColor: '#eeeeee',
borderColor: '#666666',
borderWidth: 5,
borderTopWidth: 20,
borderRadius: 10,
borderBottomRightRadius: 20,
padding: 10,
paddingTop: 20,
}}
testID="multiline_textinput_with_flex"
multiline={true}
placeholder="Placeholder defines intrinsic size"
/>
</View>
</View>
);
}