Removed RTL workaround in RCTShadowText

Reviewed By: fkgozali

Differential Revision: D4511274

fbshipit-source-id: f658afb4e1c943cc9ecab2dd2a91f251edd3fa36
This commit is contained in:
Valentin Shergin 2017-02-13 11:59:06 -08:00 committed by Facebook Github Bot
parent ea6845ca22
commit 7686274e13
5 changed files with 82 additions and 61 deletions

View File

@ -43,6 +43,8 @@ const {
Switch,
View,
} = ReactNative;
const Platform = require('Platform');
const UIExplorerPage = require('./UIExplorerPage');
const UIExplorerBlock = require('./UIExplorerBlock');
@ -100,10 +102,15 @@ function TextAlignmentExample(props) {
Left-to-Right language without text alignment.
</Text>
<Text style={props.style}>
{'\u0645\u0646 \u0627\u0644\u064A\u0645\u064A\u0646 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631 \u0627\u0644\u0644\u063A\u0629 \u062F\u0648\u0646 \u0645\u062D\u0627\u0630\u0627\u0629 \u0627\u0644\u0646\u0635'}
{'\u0645\u0646 \u0627\u0644\u064A\u0645\u064A\u0646 ' +
'\u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631 ' +
'\u0627\u0644\u0644\u063A\u0629 \u062F\u0648\u0646 ' +
'\u0645\u062D\u0627\u0630\u0627\u0629 \u0627\u0644\u0646\u0635'}
</Text>
<Text style={props.style}>
{'\u05DE\u05D9\u05DE\u05D9\u05DF \u05DC\u05E9\u05DE\u05D0\u05DC \u05D4\u05E9\u05E4\u05D4 \u05D1\u05DC\u05D9 \u05D9\u05D9\u05E9\u05D5\u05E8 \u05D8\u05E7\u05E1\u05D8'}
{'\u05DE\u05D9\u05DE\u05D9\u05DF \u05DC\u05E9\u05DE\u05D0\u05DC ' +
'\u05D4\u05E9\u05E4\u05D4 \u05D1\u05DC\u05D9 ' +
'\u05D9\u05D9\u05E9\u05D5\u05E8 \u05D8\u05E7\u05E1\u05D8'}
</Text>
</View>
</UIExplorerBlock>
@ -157,7 +164,13 @@ class RTLExample extends React.Component {
render() {
return (
<ScrollView
style={styles.container}
style={[
styles.container,
// `direction` property is supported only on iOS now.
Platform.OS === 'ios' ?
{direction: this.state.isRTL ? 'rtl' : 'ltr'} :
null
]}
onLayout={this._onLayout}>
<UIExplorerPage title={'Right-to-Left (RTL) UI Layout'}>
<UIExplorerBlock title={'Current Layout Direction'}>
@ -197,14 +210,17 @@ class RTLExample extends React.Component {
<TextAlignmentExample
title={"Using textAlign: 'left'"}
description={
'In iOS, you must change active language to flip text alignment correctly.' +
'In Android, using forceRTL() flips alignment correctly.'
'In iOS/Android, text alignment flips regardless of ' +
'languages or text content.'
}
style={[styles.fontSizeSmall, styles.textAlignLeft]}
/>
<TextAlignmentExample
title={"Using textAlign: 'right'"}
description={'In iOS/Android, text alignment flips regardless of languages or text content.'}
description={
'In iOS/Android, text alignment flips regardless of ' +
'languages or text content.'
}
style={[styles.fontSizeSmall, styles.textAlignRight]}
/>
<UIExplorerBlock title={'Working With Icons'}>
@ -235,7 +251,12 @@ class RTLExample extends React.Component {
<View Style={styles.view}>
<AnimationBlock
onPress={this._linearTap}
imgStyle={{transform: [{translateX: this.state.linear}, {scaleX: IS_RTL ? -1 : 1}]}}
imgStyle={{
transform: [
{translateX: this.state.linear},
{scaleX: IS_RTL ? -1 : 1}
]
}}
/>
</View>
</UIExplorerBlock>
@ -268,7 +289,8 @@ class RTLExample extends React.Component {
},
});
const offset = IMAGE_SIZE[0] / SCALE / 2 + 10;
const toMaxDistance = (IS_RTL ? -1 : 1) * (this.state.windowWidth / 2 - offset);
const toMaxDistance =
(IS_RTL ? -1 : 1) * (this.state.windowWidth / 2 - offset);
Animated.timing(this.state.linear, {
toValue: this.state.toggleStatus[refName] ? toMaxDistance : 0,
duration: 2000,

View File

@ -150,7 +150,6 @@ var styles = StyleSheet.create({
fontSize: 16,
fontWeight: 'bold',
margin: 5,
textAlign: 'left',
},
button: {
margin: 5,

View File

@ -37,6 +37,7 @@ CGFloat const RCTTextAutoSizeGranularity = 0.001f;
CGFloat _cachedTextStorageWidthMode;
NSAttributedString *_cachedAttributedString;
CGFloat _effectiveLetterSpacing;
UIUserInterfaceLayoutDirection _cachedEffectiveLayoutDirection;
}
static YGSize RCTMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode)
@ -68,7 +69,12 @@ static YGSize RCTMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, f
_cachedTextStorageWidth = -1;
_cachedTextStorageWidthMode = -1;
_fontSizeMultiplier = 1.0;
_textAlign = NSTextAlignmentNatural;
_writingDirection = NSWritingDirectionNatural;
_cachedEffectiveLayoutDirection = UIUserInterfaceLayoutDirectionLeftToRight;
YGNodeSetMeasureFunc(self.cssNode, RCTMeasure);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(contentSizeMultiplierDidChange:)
name:RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification
@ -189,7 +195,12 @@ static YGSize RCTMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, f
- (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(YGMeasureMode)widthMode
{
if (_cachedTextStorage && width == _cachedTextStorageWidth && widthMode == _cachedTextStorageWidthMode) {
if (
_cachedTextStorage &&
width == _cachedTextStorageWidth &&
widthMode == _cachedTextStorageWidthMode &&
_cachedEffectiveLayoutDirection == self.effectiveLayoutDirection
) {
return _cachedTextStorage;
}
@ -256,10 +267,16 @@ static YGSize RCTMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, f
backgroundColor:(UIColor *)backgroundColor
opacity:(CGFloat)opacity
{
if (![self isTextDirty] && _cachedAttributedString) {
if (
![self isTextDirty] &&
_cachedAttributedString &&
_cachedEffectiveLayoutDirection == self.effectiveLayoutDirection
) {
return _cachedAttributedString;
}
_cachedEffectiveLayoutDirection = self.effectiveLayoutDirection;
if (_fontSize && !isnan(_fontSize)) {
fontSize = @(_fontSize);
}
@ -367,80 +384,61 @@ static YGSize RCTMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, f
* varying lineHeights, we simply take the max.
*/
- (void)_setParagraphStyleOnAttributedString:(NSMutableAttributedString *)attributedString
fontLineHeight:(CGFloat)fontLineHeight
fontLineHeight:(CGFloat)fontLineHeight
heightOfTallestSubview:(CGFloat)heightOfTallestSubview
{
// check if we have lineHeight set on self
__block BOOL hasParagraphStyle = NO;
if (_lineHeight || _textAlign) {
if (_lineHeight != 0.0 || _textAlign != NSTextAlignmentNatural) {
hasParagraphStyle = YES;
}
__block float newLineHeight = _lineHeight ?: 0.0;
CGFloat fontSizeMultiplier = _allowFontScaling ? _fontSizeMultiplier : 1.0;
// check for lineHeight on each of our children, update the max as we go (in self.lineHeight)
[attributedString enumerateAttribute:NSParagraphStyleAttributeName inRange:(NSRange){0, attributedString.length} options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {
if (value) {
NSParagraphStyle *paragraphStyle = (NSParagraphStyle *)value;
CGFloat maximumLineHeight = round(paragraphStyle.maximumLineHeight / fontSizeMultiplier);
if (maximumLineHeight > newLineHeight) {
newLineHeight = maximumLineHeight;
}
hasParagraphStyle = YES;
// Text line height
__block float compoundLineHeight = _lineHeight * fontSizeMultiplier;
// Checking for `maximumLineHeight` on each of our children and updating `compoundLineHeight` with the maximum value on the go.
[attributedString enumerateAttribute:NSParagraphStyleAttributeName
inRange:(NSRange){0, attributedString.length}
options:0
usingBlock:^(NSParagraphStyle *paragraphStyle, NSRange range, BOOL *stop) {
if (!paragraphStyle) {
return;
}
hasParagraphStyle = YES;
compoundLineHeight = MAX(compoundLineHeight, paragraphStyle.maximumLineHeight);
}];
if (self.lineHeight != newLineHeight) {
self.lineHeight = newLineHeight;
}
compoundLineHeight = MAX(round(compoundLineHeight), ceilf(heightOfTallestSubview));
NSTextAlignment newTextAlign = _textAlign ?: NSTextAlignmentNatural;
// The part below is to address textAlign for RTL language before setting paragraph style
// Since we can't get layout directly because this logic is currently run just before layout is calculatede
// We will climb up to the first node which style has been setted as non-inherit
if (newTextAlign == NSTextAlignmentRight || newTextAlign == NSTextAlignmentLeft) {
RCTShadowView *view = self;
while (view != nil && YGNodeStyleGetDirection(view.cssNode) == YGDirectionInherit) {
view = [view reactSuperview];
}
if (view != nil && YGNodeStyleGetDirection(view.cssNode) == YGDirectionRTL) {
if (newTextAlign == NSTextAlignmentRight) {
newTextAlign = NSTextAlignmentLeft;
} else if (newTextAlign == NSTextAlignmentLeft) {
newTextAlign = NSTextAlignmentRight;
// Text alignment
NSTextAlignment textAlign = _textAlign;
if (textAlign == NSTextAlignmentRight || textAlign == NSTextAlignmentLeft) {
if (_cachedEffectiveLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
if (textAlign == NSTextAlignmentRight) {
textAlign = NSTextAlignmentLeft;
} else {
textAlign = NSTextAlignmentRight;
}
}
}
if (self.textAlign != newTextAlign) {
self.textAlign = newTextAlign;
}
NSWritingDirection newWritingDirection = _writingDirection ?: NSWritingDirectionNatural;
if (self.writingDirection != newWritingDirection) {
self.writingDirection = newWritingDirection;
}
// if we found anything, set it :D
if (hasParagraphStyle) {
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
paragraphStyle.alignment = _textAlign;
paragraphStyle.alignment = textAlign;
paragraphStyle.baseWritingDirection = _writingDirection;
CGFloat lineHeight = round(_lineHeight * fontSizeMultiplier);
if (heightOfTallestSubview > lineHeight) {
lineHeight = ceilf(heightOfTallestSubview);
}
paragraphStyle.minimumLineHeight = lineHeight;
paragraphStyle.maximumLineHeight = lineHeight;
paragraphStyle.minimumLineHeight = compoundLineHeight;
paragraphStyle.maximumLineHeight = compoundLineHeight;
[attributedString addAttribute:NSParagraphStyleAttributeName
value:paragraphStyle
range:(NSRange){0, attributedString.length}];
if (lineHeight > fontLineHeight) {
if (compoundLineHeight > fontLineHeight) {
[attributedString addAttribute:NSBaselineOffsetAttributeName
value:@(lineHeight / 2 - fontLineHeight / 2)
value:@(compoundLineHeight / 2 - fontLineHeight / 2)
range:(NSRange){0, attributedString.length}];
}
}

View File

@ -441,6 +441,8 @@ static void RCTProcessMetaPropsBorder(const YGValue metaProps[META_PROP_COUNT],
// Layout Direction
- (UIUserInterfaceLayoutDirection)effectiveLayoutDirection {
// Even if `YGNodeLayoutGetDirection` can return `YGDirectionInherit` here, it actually means
// that Yoga will use LTR layout for the view (even if layout process is not finished yet).
return YGNodeLayoutGetDirection(self.cssNode) == YGDirectionRTL ? UIUserInterfaceLayoutDirectionRightToLeft : UIUserInterfaceLayoutDirectionLeftToRight;
}