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 {

File diff suppressed because it is too large Load Diff

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;