Re-render views when direction changes

Summary:
This is required for D5874536, wherein I'll be introducing direction-aware props for borders.

When a view's border changes due to a direction update, only the frames of its children update. Therefore, only the children `UIView`s get a chance to be re-rendered. This is incorrect because the view that's had its borders changed also needs to re-render. So, I keep a track of the layout direction in a property on all shadow views. Then, when I update that prop within `applyLayoutNode`, I push shadow views into the `viewsWithNewFrames` set.

Reviewed By: mmmulani

Differential Revision: D5944488

fbshipit-source-id: 3f23e9973f3555612920703cdb6cec38e6360d2d
This commit is contained in:
Ramanpreet Nara 2017-10-02 11:03:00 -07:00 committed by Facebook Github Bot
parent 53a339a459
commit 9bbc70c442
6 changed files with 631 additions and 443 deletions

View File

@ -38,7 +38,7 @@ static CGFloat const kAutoSizeGranularity = 0.001f;
CGFloat _cachedTextStorageWidthMode;
NSAttributedString *_cachedAttributedString;
CGFloat _effectiveLetterSpacing;
UIUserInterfaceLayoutDirection _cachedEffectiveLayoutDirection;
UIUserInterfaceLayoutDirection _cachedLayoutDirection;
}
static YGSize RCTMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode)
@ -72,7 +72,7 @@ static YGSize RCTMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, f
_fontSizeMultiplier = 1.0;
_textAlign = NSTextAlignmentNatural;
_writingDirection = NSWritingDirectionNatural;
_cachedEffectiveLayoutDirection = UIUserInterfaceLayoutDirectionLeftToRight;
_cachedLayoutDirection = UIUserInterfaceLayoutDirectionLeftToRight;
YGNodeSetMeasureFunc(self.yogaNode, RCTMeasure);
@ -198,7 +198,7 @@ static YGSize RCTMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, f
_cachedTextStorage &&
(width == _cachedTextStorageWidth || (isnan(width) && isnan(_cachedTextStorageWidth))) &&
widthMode == _cachedTextStorageWidthMode &&
_cachedEffectiveLayoutDirection == self.effectiveLayoutDirection
_cachedLayoutDirection == self.layoutDirection
) {
return _cachedTextStorage;
}
@ -272,12 +272,12 @@ static YGSize RCTMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, f
if (
![self isTextDirty] &&
_cachedAttributedString &&
_cachedEffectiveLayoutDirection == self.effectiveLayoutDirection
_cachedLayoutDirection == self.layoutDirection
) {
return _cachedAttributedString;
}
_cachedEffectiveLayoutDirection = self.effectiveLayoutDirection;
_cachedLayoutDirection = self.layoutDirection;
if (_fontSize && !isnan(_fontSize)) {
fontSize = @(_fontSize);
@ -419,7 +419,7 @@ static YGSize RCTMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, f
// Text alignment
NSTextAlignment textAlign = _textAlign;
if (textAlign == NSTextAlignmentRight || textAlign == NSTextAlignmentLeft) {
if (_cachedEffectiveLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
if (_cachedLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
if (textAlign == NSTextAlignmentRight) {
textAlign = NSTextAlignmentLeft;
} else {

View File

@ -7,6 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory.
*
* @flow
* @format
* @providesModule TextExample
*/
'use strict';
@ -15,13 +16,56 @@ const Platform = require('Platform');
var React = require('react');
var createReactClass = require('create-react-class');
var ReactNative = require('react-native');
var {
Image,
StyleSheet,
Text,
View,
LayoutAnimation,
} = ReactNative;
var {Image, Text, View, LayoutAnimation, Button} = ReactNative;
type TextAlignExampleRTLState = {|
isRTL: boolean,
|};
class TextAlignRTLExample extends React.Component<*, TextAlignExampleRTLState> {
constructor(...args: Array<*>) {
super(...args);
this.state = {
isRTL: false,
};
}
render() {
const {isRTL} = this.state;
const toggleRTL = () => this.setState({isRTL: !isRTL});
return (
<View style={{direction: isRTL ? 'rtl' : 'ltr'}}>
<Text>auto (default) - english LTR</Text>
<Text>
\u0623\u062D\u0628 \u0627\u0644\u0644\u063A\u0629
\u0627\u0644\u0639\u0631\u0628\u064A\u0629 auto (default) - arabic RTL
</Text>
<Text style={{textAlign: 'left'}}>
left left left left left left left left left left left left left left
left
</Text>
<Text style={{textAlign: 'center'}}>
center center center center center center center center center center
center
</Text>
<Text style={{textAlign: 'right'}}>
right right right right right right right right right right right
right right
</Text>
<Text style={{textAlign: 'justify'}}>
justify: this text component{"'"}s contents are laid out with
"textAlign: justify" and as you can see all of the lines except the
last one span the available width of the parent container.
</Text>
<Button
onPress={toggleRTL}
title={`Switch to ${isRTL ? 'LTR' : 'RTL'}`}
/>
</View>
);
}
}
class Entity extends React.Component<$FlowFixMeProps> {
render() {
@ -38,25 +82,31 @@ class AttributeToggler extends React.Component<{}, $FlowFixMeState> {
toggleWeight = () => {
this.setState({
fontWeight: this.state.fontWeight === 'bold' ? 'normal' : 'bold'
fontWeight: this.state.fontWeight === 'bold' ? 'normal' : 'bold',
});
};
increaseSize = () => {
this.setState({
fontSize: this.state.fontSize + 1
fontSize: this.state.fontSize + 1,
});
};
render() {
var curStyle = {fontWeight: this.state.fontWeight, fontSize: this.state.fontSize};
var curStyle = {
fontWeight: this.state.fontWeight,
fontSize: this.state.fontSize,
};
return (
<View>
<Text style={curStyle}>
Tap the controls below to change attributes.
</Text>
<Text>
<Text>See how it will even work on <Text style={curStyle}>this nested text</Text></Text>
<Text>
See how it will even work on{' '}
<Text style={curStyle}>this nested text</Text>
</Text>
</Text>
<Text
style={{backgroundColor: '#ffaaaa', marginTop: 5}}
@ -76,14 +126,14 @@ class AttributeToggler extends React.Component<{}, $FlowFixMeState> {
var AdjustingFontSize = createReactClass({
displayName: 'AdjustingFontSize',
getInitialState: function() {
return {dynamicText:'', shouldRender: true,};
return {dynamicText: '', shouldRender: true};
},
reset: function() {
LayoutAnimation.easeInEaseOut();
this.setState({
shouldRender: false,
});
setTimeout(()=>{
setTimeout(() => {
LayoutAnimation.easeInEaseOut();
this.setState({
dynamicText: '',
@ -93,82 +143,104 @@ var AdjustingFontSize = createReactClass({
},
addText: function() {
this.setState({
dynamicText: this.state.dynamicText + (Math.floor((Math.random() * 10) % 2) ? ' foo' : ' bar'),
dynamicText:
this.state.dynamicText +
(Math.floor((Math.random() * 10) % 2) ? ' foo' : ' bar'),
});
},
removeText: function() {
this.setState({
dynamicText: this.state.dynamicText.slice(0, this.state.dynamicText.length - 4),
dynamicText: this.state.dynamicText.slice(
0,
this.state.dynamicText.length - 4,
),
});
},
render: function() {
if (!this.state.shouldRender) {
return (<View/>);
return <View />;
}
return (
<View>
<Text ellipsizeMode="tail" numberOfLines={1} style={{fontSize: 36, marginVertical: 6}}>
<Text
ellipsizeMode="tail"
numberOfLines={1}
style={{fontSize: 36, marginVertical: 6}}>
Truncated text is baaaaad.
</Text>
<Text numberOfLines={1} adjustsFontSizeToFit={true} style={{fontSize: 40, marginVertical:6}}>
<Text
numberOfLines={1}
adjustsFontSizeToFit={true}
style={{fontSize: 40, marginVertical: 6}}>
Shrinking to fit available space is much better!
</Text>
<Text adjustsFontSizeToFit={true} numberOfLines={1} style={{fontSize:30, marginVertical:6}}>
<Text
adjustsFontSizeToFit={true}
numberOfLines={1}
style={{fontSize: 30, marginVertical: 6}}>
{'Add text to me to watch me shrink!' + ' ' + this.state.dynamicText}
</Text>
<Text adjustsFontSizeToFit={true} numberOfLines={4} style={{fontSize:20, marginVertical:6}}>
{'Multiline text component shrinking is supported, watch as this reeeeaaaally loooooong teeeeeeext grooooows and then shriiiinks as you add text to me! ioahsdia soady auydoa aoisyd aosdy ' + ' ' + this.state.dynamicText}
<Text
adjustsFontSizeToFit={true}
numberOfLines={4}
style={{fontSize: 20, marginVertical: 6}}>
{'Multiline text component shrinking is supported, watch as this reeeeaaaally loooooong teeeeeeext grooooows and then shriiiinks as you add text to me! ioahsdia soady auydoa aoisyd aosdy ' +
' ' +
this.state.dynamicText}
</Text>
<Text adjustsFontSizeToFit={true} numberOfLines={1} style={{marginVertical:6}}>
<Text style={{fontSize:14}}>
<Text
adjustsFontSizeToFit={true}
numberOfLines={1}
style={{marginVertical: 6}}>
<Text style={{fontSize: 14}}>
{'Differently sized nested elements will shrink together. '}
</Text>
<Text style={{fontSize:20}}>
<Text style={{fontSize: 20}}>
{'LARGE TEXT! ' + this.state.dynamicText}
</Text>
</Text>
<View style={{flexDirection:'row', justifyContent:'space-around', marginTop: 5, marginVertical:6}}>
<Text
style={{backgroundColor: '#ffaaaa'}}
onPress={this.reset}>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-around',
marginTop: 5,
marginVertical: 6,
}}>
<Text style={{backgroundColor: '#ffaaaa'}} onPress={this.reset}>
Reset
</Text>
<Text
style={{backgroundColor: '#aaaaff'}}
onPress={this.removeText}>
<Text style={{backgroundColor: '#aaaaff'}} onPress={this.removeText}>
Remove Text
</Text>
<Text
style={{backgroundColor: '#aaffaa'}}
onPress={this.addText}>
<Text style={{backgroundColor: '#aaffaa'}} onPress={this.addText}>
Add Text
</Text>
</View>
</View>
);
}
},
});
exports.title = '<Text>';
exports.description = 'Base component for rendering styled text.';
exports.displayName = 'TextExample';
exports.examples = [
{
{
title: 'Wrap',
render: function() {
return (
<Text>
The text should wrap if it goes on multiple lines. See, this is going to
the next line.
The text should wrap if it goes on multiple lines. See, this is going
to the next line.
</Text>
);
},
}, {
},
{
title: 'Padding',
render: function() {
return (
@ -177,61 +249,63 @@ exports.examples = [
</Text>
);
},
}, {
},
{
title: 'Font Family',
render: function() {
return (
<View>
<Text style={{fontFamily: (Platform.isTVOS ? 'Times' : 'Cochin')}}>
<Text style={{fontFamily: Platform.isTVOS ? 'Times' : 'Cochin'}}>
Cochin
</Text>
<Text style={{fontFamily: (Platform.isTVOS ? 'Times' : 'Cochin'), fontWeight: 'bold'}}>
<Text
style={{
fontFamily: Platform.isTVOS ? 'Times' : 'Cochin',
fontWeight: 'bold',
}}>
Cochin bold
</Text>
<Text style={{fontFamily: 'Helvetica'}}>
Helvetica
</Text>
<Text style={{fontFamily: 'Helvetica'}}>Helvetica</Text>
<Text style={{fontFamily: 'Helvetica', fontWeight: 'bold'}}>
Helvetica bold
</Text>
<Text style={{fontFamily: (Platform.isTVOS ? 'Courier' : 'Verdana')}}>
<Text style={{fontFamily: Platform.isTVOS ? 'Courier' : 'Verdana'}}>
Verdana
</Text>
<Text style={{fontFamily: (Platform.isTVOS ? 'Courier' : 'Verdana'), fontWeight: 'bold'}}>
<Text
style={{
fontFamily: Platform.isTVOS ? 'Courier' : 'Verdana',
fontWeight: 'bold',
}}>
Verdana bold
</Text>
</View>
);
},
}, {
},
{
title: 'Font Size',
render: function() {
return (
<View>
<Text style={{fontSize: 23}}>
Size 23
</Text>
<Text style={{fontSize: 8}}>
Size 8
</Text>
<Text style={{fontSize: 23}}>Size 23</Text>
<Text style={{fontSize: 8}}>Size 8</Text>
</View>
);
},
}, {
},
{
title: 'Color',
render: function() {
return (
<View>
<Text style={{color: 'red'}}>
Red color
</Text>
<Text style={{color: 'blue'}}>
Blue color
</Text>
<Text style={{color: 'red'}}>Red color</Text>
<Text style={{color: 'blue'}}>Blue color</Text>
</View>
);
},
}, {
},
{
title: 'Font Weight',
render: function() {
return (
@ -254,61 +328,97 @@ exports.examples = [
</View>
);
},
}, {
},
{
title: 'Font Style',
render: function() {
return (
<View>
<Text style={{fontStyle: 'normal'}}>
Normal text
</Text>
<Text style={{fontStyle: 'italic'}}>
Italic text
</Text>
<Text style={{fontStyle: 'normal'}}>Normal text</Text>
<Text style={{fontStyle: 'italic'}}>Italic text</Text>
</View>
);
},
}, {
},
{
title: 'Selectable',
render: function() {
return (
<View>
<Text selectable={true}>
This text is <Text style={{fontWeight: 'bold'}}>selectable</Text> if you click-and-hold.
This text is <Text style={{fontWeight: 'bold'}}>selectable</Text> if
you click-and-hold.
</Text>
</View>
);
},
}, {
},
{
title: 'Text Decoration',
render: function() {
return (
<View>
<Text style={{textDecorationLine: 'underline', textDecorationStyle: 'solid'}}>
<Text
style={{
textDecorationLine: 'underline',
textDecorationStyle: 'solid',
}}>
Solid underline
</Text>
<Text style={{textDecorationLine: 'underline', textDecorationStyle: 'double', textDecorationColor: '#ff0000'}}>
<Text
style={{
textDecorationLine: 'underline',
textDecorationStyle: 'double',
textDecorationColor: '#ff0000',
}}>
Double underline with custom color
</Text>
<Text style={{textDecorationLine: 'underline', textDecorationStyle: 'dashed', textDecorationColor: '#9CDC40'}}>
<Text
style={{
textDecorationLine: 'underline',
textDecorationStyle: 'dashed',
textDecorationColor: '#9CDC40',
}}>
Dashed underline with custom color
</Text>
<Text style={{textDecorationLine: 'underline', textDecorationStyle: 'dotted', textDecorationColor: 'blue'}}>
<Text
style={{
textDecorationLine: 'underline',
textDecorationStyle: 'dotted',
textDecorationColor: 'blue',
}}>
Dotted underline with custom color
</Text>
<Text style={{textDecorationLine: 'none'}}>
None textDecoration
</Text>
<Text style={{textDecorationLine: 'line-through', textDecorationStyle: 'solid'}}>
<Text style={{textDecorationLine: 'none'}}>None textDecoration</Text>
<Text
style={{
textDecorationLine: 'line-through',
textDecorationStyle: 'solid',
}}>
Solid line-through
</Text>
<Text style={{textDecorationLine: 'line-through', textDecorationStyle: 'double', textDecorationColor: '#ff0000'}}>
<Text
style={{
textDecorationLine: 'line-through',
textDecorationStyle: 'double',
textDecorationColor: '#ff0000',
}}>
Double line-through with custom color
</Text>
<Text style={{textDecorationLine: 'line-through', textDecorationStyle: 'dashed', textDecorationColor: '#9CDC40'}}>
<Text
style={{
textDecorationLine: 'line-through',
textDecorationStyle: 'dashed',
textDecorationColor: '#9CDC40',
}}>
Dashed line-through with custom color
</Text>
<Text style={{textDecorationLine: 'line-through', textDecorationStyle: 'dotted', textDecorationColor: 'blue'}}>
<Text
style={{
textDecorationLine: 'line-through',
textDecorationStyle: 'dotted',
textDecorationColor: 'blue',
}}>
Dotted line-through with custom color
</Text>
<Text style={{textDecorationLine: 'underline line-through'}}>
@ -317,9 +427,11 @@ exports.examples = [
</View>
);
},
}, {
},
{
title: 'Nested',
description: 'Nested text components will inherit the styles of their ' +
description:
'Nested text components will inherit the styles of their ' +
'parents (only backgroundColor is inherited from non-Text parents). ' +
'<Text> only supports other <Text> and raw text (strings) as children.',
render: function() {
@ -336,13 +448,13 @@ exports.examples = [
</Text>
)
</Text>
<Text style={{opacity:0.7}}>
<Text style={{opacity: 0.7}}>
(opacity
<Text>
(is inherited
<Text style={{opacity:0.7}}>
<Text style={{opacity: 0.7}}>
(and accumulated
<Text style={{backgroundColor:'#ffaaaa'}}>
<Text style={{backgroundColor: '#ffaaaa'}}>
(and also applies to the background)
</Text>
)
@ -357,42 +469,51 @@ exports.examples = [
</View>
);
},
}, {
},
{
title: 'Text Align',
render: function() {
return (
<View>
<Text>auto (default) - english LTR</Text>
<Text>
auto (default) - english LTR
</Text>
<Text>
أحب اللغة العربية auto (default) - arabic RTL
\u0623\u062D\u0628 \u0627\u0644\u0644\u063A\u0629
\u0627\u0644\u0639\u0631\u0628\u064A\u0629 auto (default) - arabic
RTL
</Text>
<Text style={{textAlign: 'left'}}>
left left left left left left left left left left left left left left left
left left left left left left left left left left left left left
left left
</Text>
<Text style={{textAlign: 'center'}}>
center center center center center center center center center center center
center center center center center center center center center
center center
</Text>
<Text style={{textAlign: 'right'}}>
right right right right right right right right right right right right right
right right right right right right right right right right right
right right
</Text>
<Text style={{textAlign: 'justify'}}>
justify: this text component{"'"}s contents are laid out with "textAlign: justify"
and as you can see all of the lines except the last one span the
available width of the parent container.
justify: this text component{"'"}s contents are laid out with
"textAlign: justify" and as you can see all of the lines except the
last one span the available width of the parent container.
</Text>
</View>
);
},
}, {
},
{
title: 'Text Align with RTL',
render: function() {
return <TextAlignRTLExample />;
},
},
{
title: 'Letter Spacing',
render: function() {
return (
<View>
<Text style={{letterSpacing: 0}}>
letterSpacing = 0
</Text>
<Text style={{letterSpacing: 0}}>letterSpacing = 0</Text>
<Text style={{letterSpacing: 2, marginTop: 5}}>
letterSpacing = 2
</Text>
@ -405,16 +526,18 @@ exports.examples = [
</View>
);
},
}, {
},
{
title: 'Spaces',
render: function() {
return (
<Text>
A {'generated'} {' '} {'string'} and some &nbsp;&nbsp;&nbsp; spaces
A {'generated'} {'string'} and some &nbsp;&nbsp;&nbsp; spaces
</Text>
);
},
}, {
},
{
title: 'Line Height',
render: function() {
return (
@ -426,20 +549,21 @@ exports.examples = [
</Text>
);
},
}, {
title: 'Empty Text',
description: 'It\'s ok to have Text with zero or null children.',
render: function() {
return (
<Text />
);
},
}, {
{
title: 'Empty Text',
description: "It's ok to have Text with zero or null children.",
render: function() {
return <Text />;
},
},
{
title: 'Toggling Attributes',
render: function(): React.Element<any> {
return <AttributeToggler />;
},
}, {
},
{
title: 'backgroundColor attribute',
description: 'backgroundColor is inherited from all types of views.',
render: function() {
@ -447,13 +571,17 @@ exports.examples = [
<Text style={{backgroundColor: 'yellow'}}>
Yellow container background,
<Text style={{backgroundColor: '#ffaaaa'}}>
{' '}red background,
{' '}
red background,
<Text style={{backgroundColor: '#aaaaff'}}>
{' '}blue background,
{' '}
blue background,
<Text>
{' '}inherited blue background,
{' '}
inherited blue background,
<Text style={{backgroundColor: '#aaffaa'}}>
{' '}nested green background.
{' '}
nested green background.
</Text>
</Text>
</Text>
@ -461,44 +589,70 @@ exports.examples = [
</Text>
);
},
}, {
},
{
title: 'numberOfLines attribute',
render: function() {
return (
<View>
<Text numberOfLines={1}>
Maximum of one line, no matter how much I write here. If I keep writing, it{"'"}ll just truncate after one line.
Maximum of one line, no matter how much I write here. If I keep
writing, it{"'"}ll just truncate after one line.
</Text>
<Text numberOfLines={2} style={{marginTop: 20}}>
Maximum of two lines, no matter how much I write here. If I keep writing, it{"'"}ll just truncate after two lines.
Maximum of two lines, no matter how much I write here. If I keep
writing, it{"'"}ll just truncate after two lines.
</Text>
<Text style={{marginTop: 20}}>
No maximum lines specified, no matter how much I write here. If I keep writing, it{"'"}ll just keep going and going.
No maximum lines specified, no matter how much I write here. If I
keep writing, it{"'"}ll just keep going and going.
</Text>
</View>
);
},
}, {
},
{
title: 'Text highlighting (tap the link to see highlight)',
render: function() {
return (
<View>
<Text>Lorem ipsum dolor sit amet, <Text suppressHighlighting={false} style={{backgroundColor: 'white', textDecorationLine: 'underline', color: 'blue'}} onPress={() => null}>consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud</Text> exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</Text>
<Text>
Lorem ipsum dolor sit amet,{' '}
<Text
suppressHighlighting={false}
style={{
backgroundColor: 'white',
textDecorationLine: 'underline',
color: 'blue',
}}
onPress={() => null}>
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud
</Text>{' '}
exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</Text>
</View>
);
},
}, {
},
{
title: 'allowFontScaling attribute',
render: function() {
return (
<View>
<Text>
By default, text will respect Text Size accessibility setting on iOS.
It means that all font sizes will be increased or descreased depending on the value of Text Size setting in
{" "}<Text style={{fontWeight: 'bold'}}>Settings.app - Display & Brightness - Text Size</Text>
By default, text will respect Text Size accessibility setting on
iOS. It means that all font sizes will be increased or descreased
depending on the value of Text Size setting in{' '}
<Text style={{fontWeight: 'bold'}}>
Settings.app - Display & Brightness - Text Size
</Text>
</Text>
<Text style={{marginTop: 10}}>
You can disable scaling for your Text component by passing {"\""}allowFontScaling={"{"}false{"}\""} prop.
You can disable scaling for your Text component by passing {'"'}allowFontScaling={'{'}false{'}"'}{' '}
prop.
</Text>
<Text allowFontScaling={false} style={{marginTop: 20}}>
This text will not scale.
@ -506,30 +660,46 @@ exports.examples = [
</View>
);
},
}, {
},
{
title: 'Inline views',
render: function() {
return (
<View>
<Text>
This text contains an inline blue view <View style={{width: 25, height: 25, backgroundColor: 'steelblue'}} /> and
an inline image <Image source={require('./flux.png')} style={{width: 30, height: 11, resizeMode: 'cover'}}/>. Neat, huh?
This text contains an inline blue view{' '}
<View
style={{width: 25, height: 25, backgroundColor: 'steelblue'}}
/>{' '}
and an inline image{' '}
<Image
source={require('./flux.png')}
style={{width: 30, height: 11, resizeMode: 'cover'}}
/>. Neat, huh?
</Text>
</View>
);
},
}, {
},
{
title: 'Text shadow',
render: function() {
return (
<View>
<Text style={{fontSize: 20, textShadowOffset: {width: 2, height: 2}, textShadowRadius: 1, textShadowColor: '#00cccc'}}>
<Text
style={{
fontSize: 20,
textShadowOffset: {width: 2, height: 2},
textShadowRadius: 1,
textShadowColor: '#00cccc',
}}>
Demo text shadow
</Text>
</View>
);
},
}, {
},
{
title: 'Ellipsize mode',
render: function() {
return (
@ -549,18 +719,25 @@ exports.examples = [
</View>
);
},
}, {
},
{
title: 'Font variants',
render: function() {
return (
<View>
<Text style={{fontVariant: ['small-caps']}}>
Small Caps{'\n'}
</Text>
<Text style={{fontFamily: (Platform.isTVOS ? 'Times' : 'Hoefler Text'), fontVariant: ['oldstyle-nums']}}>
<Text style={{fontVariant: ['small-caps']}}>Small Caps{'\n'}</Text>
<Text
style={{
fontFamily: Platform.isTVOS ? 'Times' : 'Hoefler Text',
fontVariant: ['oldstyle-nums'],
}}>
Old Style nums 0123456789{'\n'}
</Text>
<Text style={{fontFamily: (Platform.isTVOS ? 'Times' : 'Hoefler Text'), fontVariant: ['lining-nums']}}>
<Text
style={{
fontFamily: Platform.isTVOS ? 'Times' : 'Hoefler Text',
fontVariant: ['lining-nums'],
}}>
Lining nums 0123456789{'\n'}
</Text>
<Text style={{fontVariant: ['tabular-nums']}}>
@ -576,9 +753,11 @@ exports.examples = [
</View>
);
},
}, {
},
{
title: 'Dynamic Font Size Adjustment',
render: function(): React.Element<any> {
return <AdjustingFontSize />;
},
}];
},
];

View File

@ -494,7 +494,7 @@ static NSDictionary *deviceOrientationEventBody(UIDeviceOrientation orientation)
reactTags[index] = shadowView.reactTag;
frameDataArray[index++] = (RCTFrameData){
shadowView.frame,
shadowView.effectiveLayoutDirection,
shadowView.layoutDirection,
shadowView.isNewView,
shadowView.superview.isNewView,
shadowView.isHidden,

View File

@ -27,7 +27,7 @@
absolutePosition:(CGPoint)absolutePosition
{
// Call super method if LTR layout is enforced.
if (self.effectiveLayoutDirection == UIUserInterfaceLayoutDirectionLeftToRight) {
if (self.layoutDirection == UIUserInterfaceLayoutDirectionLeftToRight) {
[super applyLayoutNode:node
viewsWithNewFrame:viewsWithNewFrame
absolutePosition:absolutePosition];

View File

@ -84,9 +84,10 @@ typedef void (^RCTApplierBlock)(NSDictionary<NSNumber *, UIView *> *viewRegistry
@property (nonatomic, assign, getter=isHidden) BOOL hidden;
/**
* Computed layout direction for the view backed to Yoga node value.
* Layout direction for the view as computed in applyLayoutNode.
*/
@property (nonatomic, assign, readonly) UIUserInterfaceLayoutDirection effectiveLayoutDirection;
@property (nonatomic, assign, readonly) UIUserInterfaceLayoutDirection layoutDirection;
/**
* Position and dimensions.
@ -187,6 +188,11 @@ typedef void (^RCTApplierBlock)(NSDictionary<NSNumber *, UIView *> *viewRegistry
*/
@property (nonatomic, assign) CGSize intrinsicContentSize;
/**
* Return the layout direction stored in the Yoga node that backs this view.
*/
- (UIUserInterfaceLayoutDirection)getLayoutDirectionFromYogaNode;
/**
* Calculate property changes that need to be propagated to the view.
* The applierBlocks set contains RCTApplierBlock functions that must be applied

View File

@ -204,8 +204,11 @@ static void RCTProcessMetaPropsBorder(const YGValue metaProps[META_PROP_COUNT],
RCTRoundPixelValue(absoluteBottomRight.y - absoluteTopLeft.y)
}};
if (!CGRectEqualToRect(frame, _frame)) {
UIUserInterfaceLayoutDirection updatedLayoutDirection = [self getLayoutDirectionFromYogaNode];
if (!CGRectEqualToRect(frame, _frame) || _layoutDirection != updatedLayoutDirection) {
_frame = frame;
_layoutDirection = updatedLayoutDirection;
[viewsWithNewFrame addObject:self];
}
@ -493,7 +496,7 @@ static void RCTProcessMetaPropsBorder(const YGValue metaProps[META_PROP_COUNT],
// Layout Direction
- (UIUserInterfaceLayoutDirection)effectiveLayoutDirection {
- (UIUserInterfaceLayoutDirection)getLayoutDirectionFromYogaNode {
// 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(_yogaNode) == YGDirectionRTL ? UIUserInterfaceLayoutDirectionRightToLeft : UIUserInterfaceLayoutDirectionLeftToRight;