2015-03-23 22:07:33 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*/
|
2015-01-30 01:10:49 +00:00
|
|
|
|
|
|
|
#import "RCTShadowView.h"
|
|
|
|
|
|
|
|
#import "RCTConvert.h"
|
2017-12-19 19:18:00 +00:00
|
|
|
#import "RCTI18nUtil.h"
|
2015-01-30 01:10:49 +00:00
|
|
|
#import "RCTLog.h"
|
|
|
|
#import "RCTUtils.h"
|
Implement CSS z-index for iOS
Summary:
This diff implement the CSS z-index for React Native iOS views. We've had numerous pull request for this feature, but they've all attempted to use the `layer.zPosition` property, which is problematic for two reasons:
1. zPosition only affects rendering order, not event processing order. Views with a higher zPosition will appear in front of others in the hierarchy, but won't be the first to receive touch events, and may be blocked by views that are visually behind them.
2. when using a perspective transform matrix, views with a nonzero zPosition will be rendered in a different position due to parallax, which probably isn't desirable.
See https://github.com/facebook/react-native/pull/7825 for further discussion of this problem.
So instead of using `layer.zPosition`, I've implemented this by actually adjusting the order of the subviews within their parent based on the zIndex. This can't be done on the JS side because it would affect layout, which is order-dependent, so I'm doing it inside the view itself.
It works as follows:
1. The `reactSubviews` array is set, whose order matches the order of the JS components and shadowView components, as specified by the UIManager.
2. `didUpdateReactSubviews` is called, which in turn calls `sortedSubviews` (which lazily generates a sorted array of `reactSubviews` by zIndex) and inserts the result into the view.
3. If a subview is added or removed, or the zIndex of any subview is changed, the previous `sortedSubviews` array is cleared and `didUpdateReactSubviews` is called again.
To demonstrate it working, I've modified the UIExplorer example from https://github.com/facebook/react-native/pull/7825
Reviewed By: javache
Differential Revision: D3365717
fbshipit-source-id: b34aa8bfad577bce023f8af5414f9b974aafd8aa
2016-06-07 14:40:25 +00:00
|
|
|
#import "UIView+Private.h"
|
2016-11-23 15:47:52 +00:00
|
|
|
#import "UIView+React.h"
|
2015-01-30 01:10:49 +00:00
|
|
|
|
|
|
|
typedef void (^RCTActionBlock)(RCTShadowView *shadowViewSelf, id value);
|
|
|
|
typedef void (^RCTResetActionBlock)(RCTShadowView *shadowViewSelf);
|
|
|
|
|
2015-08-24 10:14:33 +00:00
|
|
|
typedef NS_ENUM(unsigned int, meta_prop_t) {
|
2015-01-30 01:10:49 +00:00
|
|
|
META_PROP_LEFT,
|
|
|
|
META_PROP_TOP,
|
|
|
|
META_PROP_RIGHT,
|
|
|
|
META_PROP_BOTTOM,
|
2017-10-19 02:29:42 +00:00
|
|
|
META_PROP_START,
|
|
|
|
META_PROP_END,
|
2015-01-30 01:10:49 +00:00
|
|
|
META_PROP_HORIZONTAL,
|
|
|
|
META_PROP_VERTICAL,
|
|
|
|
META_PROP_ALL,
|
|
|
|
META_PROP_COUNT,
|
2015-08-24 10:14:33 +00:00
|
|
|
};
|
2015-01-30 01:10:49 +00:00
|
|
|
|
|
|
|
@implementation RCTShadowView
|
|
|
|
{
|
2015-03-02 19:36:55 +00:00
|
|
|
RCTUpdateLifecycle _propagationLifecycle;
|
|
|
|
RCTUpdateLifecycle _textLifecycle;
|
2015-01-30 01:10:49 +00:00
|
|
|
NSDictionary *_lastParentProperties;
|
2015-11-03 22:45:46 +00:00
|
|
|
NSMutableArray<RCTShadowView *> *_reactSubviews;
|
2015-01-30 01:10:49 +00:00
|
|
|
BOOL _recomputePadding;
|
|
|
|
BOOL _recomputeMargin;
|
2015-07-30 13:20:28 +00:00
|
|
|
BOOL _recomputeBorder;
|
2017-01-11 11:58:03 +00:00
|
|
|
YGValue _paddingMetaProps[META_PROP_COUNT];
|
|
|
|
YGValue _marginMetaProps[META_PROP_COUNT];
|
|
|
|
YGValue _borderMetaProps[META_PROP_COUNT];
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
|
2017-04-27 19:48:53 +00:00
|
|
|
+ (YGConfigRef)yogaConfig
|
|
|
|
{
|
|
|
|
static YGConfigRef yogaConfig;
|
|
|
|
static dispatch_once_t onceToken;
|
|
|
|
dispatch_once(&onceToken, ^{
|
|
|
|
yogaConfig = YGConfigNew();
|
|
|
|
// Turnig off pixel rounding.
|
|
|
|
YGConfigSetPointScaleFactor(yogaConfig, 0.0);
|
2017-04-28 13:13:51 +00:00
|
|
|
YGConfigSetUseLegacyStretchBehaviour(yogaConfig, true);
|
2017-04-27 19:48:53 +00:00
|
|
|
});
|
|
|
|
return yogaConfig;
|
|
|
|
}
|
|
|
|
|
2015-01-30 01:10:49 +00:00
|
|
|
@synthesize reactTag = _reactTag;
|
|
|
|
|
2017-02-21 16:43:34 +00:00
|
|
|
// YogaNode API
|
2015-01-30 01:10:49 +00:00
|
|
|
|
2016-12-03 12:40:18 +00:00
|
|
|
static void RCTPrint(YGNodeRef node)
|
2015-01-30 01:10:49 +00:00
|
|
|
{
|
2016-12-03 12:40:18 +00:00
|
|
|
RCTShadowView *shadowView = (__bridge RCTShadowView *)YGNodeGetContext(node);
|
2017-09-14 07:23:06 +00:00
|
|
|
printf("%s(%lld), ", shadowView.viewName.UTF8String, (long long)shadowView.reactTag.integerValue);
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 11:58:03 +00:00
|
|
|
#define RCT_SET_YGVALUE(ygvalue, setter, ...) \
|
|
|
|
switch (ygvalue.unit) { \
|
2017-02-16 14:47:28 +00:00
|
|
|
case YGUnitAuto: \
|
2017-01-11 11:58:03 +00:00
|
|
|
case YGUnitUndefined: \
|
|
|
|
setter(__VA_ARGS__, YGUndefined); \
|
|
|
|
break; \
|
2017-02-14 22:26:13 +00:00
|
|
|
case YGUnitPoint: \
|
2017-01-11 11:58:03 +00:00
|
|
|
setter(__VA_ARGS__, ygvalue.value); \
|
|
|
|
break; \
|
|
|
|
case YGUnitPercent: \
|
|
|
|
setter##Percent(__VA_ARGS__, ygvalue.value); \
|
|
|
|
break; \
|
|
|
|
}
|
|
|
|
|
2017-03-01 17:12:45 +00:00
|
|
|
#define RCT_SET_YGVALUE_AUTO(ygvalue, setter, ...) \
|
|
|
|
switch (ygvalue.unit) { \
|
|
|
|
case YGUnitAuto: \
|
|
|
|
setter##Auto(__VA_ARGS__); \
|
|
|
|
break; \
|
|
|
|
case YGUnitUndefined: \
|
|
|
|
setter(__VA_ARGS__, YGUndefined); \
|
|
|
|
break; \
|
|
|
|
case YGUnitPoint: \
|
|
|
|
setter(__VA_ARGS__, ygvalue.value); \
|
|
|
|
break; \
|
|
|
|
case YGUnitPercent: \
|
|
|
|
setter##Percent(__VA_ARGS__, ygvalue.value); \
|
|
|
|
break; \
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RCTProcessMetaPropsPadding(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node) {
|
2017-10-25 03:32:17 +00:00
|
|
|
if (![[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL]) {
|
2017-10-19 02:29:44 +00:00
|
|
|
RCT_SET_YGVALUE(metaProps[META_PROP_START], YGNodeStyleSetPadding, node, YGEdgeStart);
|
|
|
|
RCT_SET_YGVALUE(metaProps[META_PROP_END], YGNodeStyleSetPadding, node, YGEdgeEnd);
|
|
|
|
RCT_SET_YGVALUE(metaProps[META_PROP_LEFT], YGNodeStyleSetPadding, node, YGEdgeLeft);
|
|
|
|
RCT_SET_YGVALUE(metaProps[META_PROP_RIGHT], YGNodeStyleSetPadding, node, YGEdgeRight);
|
|
|
|
} else {
|
|
|
|
YGValue start = metaProps[META_PROP_START].unit == YGUnitUndefined ? metaProps[META_PROP_LEFT] : metaProps[META_PROP_START];
|
|
|
|
YGValue end = metaProps[META_PROP_END].unit == YGUnitUndefined ? metaProps[META_PROP_RIGHT] : metaProps[META_PROP_END];
|
|
|
|
RCT_SET_YGVALUE(start, YGNodeStyleSetPadding, node, YGEdgeStart);
|
|
|
|
RCT_SET_YGVALUE(end, YGNodeStyleSetPadding, node, YGEdgeEnd);
|
|
|
|
}
|
2017-03-01 17:12:45 +00:00
|
|
|
RCT_SET_YGVALUE(metaProps[META_PROP_TOP], YGNodeStyleSetPadding, node, YGEdgeTop);
|
|
|
|
RCT_SET_YGVALUE(metaProps[META_PROP_BOTTOM], YGNodeStyleSetPadding, node, YGEdgeBottom);
|
|
|
|
RCT_SET_YGVALUE(metaProps[META_PROP_HORIZONTAL], YGNodeStyleSetPadding, node, YGEdgeHorizontal);
|
|
|
|
RCT_SET_YGVALUE(metaProps[META_PROP_VERTICAL], YGNodeStyleSetPadding, node, YGEdgeVertical);
|
|
|
|
RCT_SET_YGVALUE(metaProps[META_PROP_ALL], YGNodeStyleSetPadding, node, YGEdgeAll);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RCTProcessMetaPropsMargin(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node) {
|
2017-10-25 03:32:17 +00:00
|
|
|
if (![[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL]) {
|
2017-10-19 02:29:46 +00:00
|
|
|
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_START], YGNodeStyleSetMargin, node, YGEdgeStart);
|
|
|
|
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_END], YGNodeStyleSetMargin, node, YGEdgeEnd);
|
|
|
|
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_LEFT], YGNodeStyleSetMargin, node, YGEdgeLeft);
|
|
|
|
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_RIGHT], YGNodeStyleSetMargin, node, YGEdgeRight);
|
|
|
|
} else {
|
|
|
|
YGValue start = metaProps[META_PROP_START].unit == YGUnitUndefined ? metaProps[META_PROP_LEFT] : metaProps[META_PROP_START];
|
|
|
|
YGValue end = metaProps[META_PROP_END].unit == YGUnitUndefined ? metaProps[META_PROP_RIGHT] : metaProps[META_PROP_END];
|
|
|
|
RCT_SET_YGVALUE_AUTO(start, YGNodeStyleSetMargin, node, YGEdgeStart);
|
|
|
|
RCT_SET_YGVALUE_AUTO(end, YGNodeStyleSetMargin, node, YGEdgeEnd);
|
|
|
|
}
|
2017-03-01 17:12:45 +00:00
|
|
|
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_TOP], YGNodeStyleSetMargin, node, YGEdgeTop);
|
|
|
|
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_BOTTOM], YGNodeStyleSetMargin, node, YGEdgeBottom);
|
|
|
|
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_HORIZONTAL], YGNodeStyleSetMargin, node, YGEdgeHorizontal);
|
|
|
|
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_VERTICAL], YGNodeStyleSetMargin, node, YGEdgeVertical);
|
|
|
|
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_ALL], YGNodeStyleSetMargin, node, YGEdgeAll);
|
2016-07-20 15:46:00 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 11:58:03 +00:00
|
|
|
static void RCTProcessMetaPropsBorder(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node) {
|
2017-10-25 03:32:17 +00:00
|
|
|
if (![[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL]) {
|
2017-10-19 02:29:42 +00:00
|
|
|
YGNodeStyleSetBorder(node, YGEdgeStart, metaProps[META_PROP_START].value);
|
|
|
|
YGNodeStyleSetBorder(node, YGEdgeEnd, metaProps[META_PROP_END].value);
|
|
|
|
YGNodeStyleSetBorder(node, YGEdgeLeft, metaProps[META_PROP_LEFT].value);
|
|
|
|
YGNodeStyleSetBorder(node, YGEdgeRight, metaProps[META_PROP_RIGHT].value);
|
|
|
|
} else {
|
|
|
|
const float start = YGFloatIsUndefined(metaProps[META_PROP_START].value) ? metaProps[META_PROP_LEFT].value : metaProps[META_PROP_START].value;
|
|
|
|
const float end = YGFloatIsUndefined(metaProps[META_PROP_END].value) ? metaProps[META_PROP_RIGHT].value : metaProps[META_PROP_END].value;
|
|
|
|
YGNodeStyleSetBorder(node, YGEdgeStart, start);
|
|
|
|
YGNodeStyleSetBorder(node, YGEdgeEnd, end);
|
|
|
|
}
|
2017-01-11 11:58:03 +00:00
|
|
|
YGNodeStyleSetBorder(node, YGEdgeTop, metaProps[META_PROP_TOP].value);
|
|
|
|
YGNodeStyleSetBorder(node, YGEdgeBottom, metaProps[META_PROP_BOTTOM].value);
|
|
|
|
YGNodeStyleSetBorder(node, YGEdgeHorizontal, metaProps[META_PROP_HORIZONTAL].value);
|
|
|
|
YGNodeStyleSetBorder(node, YGEdgeVertical, metaProps[META_PROP_VERTICAL].value);
|
|
|
|
YGNodeStyleSetBorder(node, YGEdgeAll, metaProps[META_PROP_ALL].value);
|
|
|
|
}
|
2015-01-30 01:10:49 +00:00
|
|
|
|
|
|
|
// The absolute stuff is so that we can take into account our absolute position when rounding in order to
|
|
|
|
// snap to the pixel grid. For example, say you have the following structure:
|
|
|
|
//
|
|
|
|
// +--------+---------+--------+
|
|
|
|
// | |+-------+| |
|
|
|
|
// | || || |
|
|
|
|
// | |+-------+| |
|
|
|
|
// +--------+---------+--------+
|
|
|
|
//
|
|
|
|
// Say the screen width is 320 pts so the three big views will get the following x bounds from our layout system:
|
|
|
|
// {0, 106.667}, {106.667, 213.333}, {213.333, 320}
|
|
|
|
//
|
|
|
|
// Assuming screen scale is 2, these numbers must be rounded to the nearest 0.5 to fit the pixel grid:
|
|
|
|
// {0, 106.5}, {106.5, 213.5}, {213.5, 320}
|
|
|
|
// You'll notice that the three widths are 106.5, 107, 106.5.
|
|
|
|
//
|
|
|
|
// This is great for the parent views but it gets trickier when we consider rounding for the subview.
|
|
|
|
//
|
|
|
|
// When we go to round the bounds for the subview in the middle, it's relative bounds are {0, 106.667}
|
|
|
|
// which gets rounded to {0, 106.5}. This will cause the subview to be one pixel smaller than it should be.
|
|
|
|
// this is why we need to pass in the absolute position in order to do the rounding relative to the screen's
|
|
|
|
// grid rather than the view's grid.
|
|
|
|
//
|
|
|
|
// After passing in the absolutePosition of {106.667, y}, we do the following calculations:
|
|
|
|
// absoluteLeft = round(absolutePosition.x + viewPosition.left) = round(106.667 + 0) = 106.5
|
2016-11-10 22:59:15 +00:00
|
|
|
// absoluteRight = round(absolutePosition.x + viewPosition.left + viewSize.left) + round(106.667 + 0 + 106.667) = 213.5
|
2015-01-30 01:10:49 +00:00
|
|
|
// width = 213.5 - 106.5 = 107
|
|
|
|
// You'll notice that this is the same width we calculated for the parent view because we've taken its position into account.
|
|
|
|
|
2016-12-03 12:40:18 +00:00
|
|
|
- (void)applyLayoutNode:(YGNodeRef)node
|
2015-11-03 22:45:46 +00:00
|
|
|
viewsWithNewFrame:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
|
2015-06-01 15:34:09 +00:00
|
|
|
absolutePosition:(CGPoint)absolutePosition
|
2015-01-30 01:10:49 +00:00
|
|
|
{
|
2016-12-03 12:40:18 +00:00
|
|
|
if (!YGNodeGetHasNewLayout(node)) {
|
2015-01-30 01:10:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-01 19:03:11 +00:00
|
|
|
RCTAssert(!YGNodeIsDirty(node), @"Attempt to get layout metrics from dirtied Yoga node.");
|
|
|
|
|
2017-06-21 00:12:51 +00:00
|
|
|
YGNodeSetHasNewLayout(node, false);
|
|
|
|
|
|
|
|
if (YGNodeStyleGetDisplay(node) == YGDisplayNone) {
|
|
|
|
// If the node is hidden (has `display: none;`), its (and its descendants)
|
|
|
|
// layout metrics are invalid and/or dirtied, so we have to stop here.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-24 07:17:57 +00:00
|
|
|
CGRect frame = CGRectMake(YGNodeLayoutGetLeft(node), YGNodeLayoutGetTop(node), YGNodeLayoutGetWidth(node), YGNodeLayoutGetHeight(node));
|
|
|
|
|
|
|
|
// 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).
|
|
|
|
UIUserInterfaceLayoutDirection layoutDirection = YGNodeLayoutGetDirection(_yogaNode) == YGDirectionRTL ? UIUserInterfaceLayoutDirectionRightToLeft : UIUserInterfaceLayoutDirectionLeftToRight;
|
|
|
|
|
|
|
|
[self applyLayoutWithFrame:frame
|
|
|
|
layoutDirection:layoutDirection
|
|
|
|
viewsWithUpdatedLayout:viewsWithNewFrame
|
|
|
|
absolutePosition:absolutePosition];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)applyLayoutWithFrame:(CGRect)frame
|
|
|
|
layoutDirection:(UIUserInterfaceLayoutDirection)layoutDirection
|
|
|
|
viewsWithUpdatedLayout:(NSMutableSet<RCTShadowView *> *)viewsWithUpdatedLayout
|
|
|
|
absolutePosition:(CGPoint)absolutePosition
|
|
|
|
{
|
2016-11-10 22:59:15 +00:00
|
|
|
CGPoint absoluteTopLeft = {
|
2018-01-24 07:17:57 +00:00
|
|
|
absolutePosition.x + frame.origin.x,
|
|
|
|
absolutePosition.y + frame.origin.y
|
2015-01-30 01:10:49 +00:00
|
|
|
};
|
2015-03-02 19:36:55 +00:00
|
|
|
|
2016-11-10 22:59:15 +00:00
|
|
|
CGPoint absoluteBottomRight = {
|
2018-01-24 07:17:57 +00:00
|
|
|
absolutePosition.x + frame.origin.x + frame.size.width,
|
|
|
|
absolutePosition.y + frame.origin.y + frame.size.height
|
2015-01-30 01:10:49 +00:00
|
|
|
};
|
2015-03-02 19:36:55 +00:00
|
|
|
|
2018-01-24 07:17:57 +00:00
|
|
|
CGRect roundedFrame = {{
|
|
|
|
RCTRoundPixelValue(frame.origin.x),
|
|
|
|
RCTRoundPixelValue(frame.origin.y),
|
2015-03-17 20:42:44 +00:00
|
|
|
}, {
|
2016-11-10 22:59:15 +00:00
|
|
|
RCTRoundPixelValue(absoluteBottomRight.x - absoluteTopLeft.x),
|
|
|
|
RCTRoundPixelValue(absoluteBottomRight.y - absoluteTopLeft.y)
|
2015-03-17 20:42:44 +00:00
|
|
|
}};
|
2015-01-30 01:10:49 +00:00
|
|
|
|
2018-01-24 07:17:57 +00:00
|
|
|
if (!CGRectEqualToRect(_frame, roundedFrame) || _layoutDirection != layoutDirection) {
|
|
|
|
_frame = roundedFrame;
|
|
|
|
_layoutDirection = layoutDirection;
|
|
|
|
[viewsWithUpdatedLayout addObject:self];
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
|
2018-01-24 07:17:57 +00:00
|
|
|
absolutePosition.x += frame.origin.x;
|
|
|
|
absolutePosition.y += frame.origin.y;
|
2015-01-30 01:10:49 +00:00
|
|
|
|
2018-01-24 07:17:57 +00:00
|
|
|
[self applyLayoutToChildren:_yogaNode
|
|
|
|
viewsWithNewFrame:viewsWithUpdatedLayout
|
|
|
|
absolutePosition:absolutePosition];
|
2016-05-31 17:18:37 +00:00
|
|
|
}
|
|
|
|
|
2016-12-03 12:40:18 +00:00
|
|
|
- (void)applyLayoutToChildren:(YGNodeRef)node
|
2016-05-31 17:18:37 +00:00
|
|
|
viewsWithNewFrame:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
|
|
|
|
absolutePosition:(CGPoint)absolutePosition
|
|
|
|
{
|
2016-12-16 12:39:13 +00:00
|
|
|
for (unsigned int i = 0; i < YGNodeGetChildCount(node); ++i) {
|
2015-01-30 01:10:49 +00:00
|
|
|
RCTShadowView *child = (RCTShadowView *)_reactSubviews[i];
|
2016-12-03 12:40:18 +00:00
|
|
|
[child applyLayoutNode:YGNodeGetChild(node, i)
|
2015-06-01 15:34:09 +00:00
|
|
|
viewsWithNewFrame:viewsWithNewFrame
|
|
|
|
absolutePosition:absolutePosition];
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-14 18:25:00 +00:00
|
|
|
- (NSDictionary<NSString *, id> *)processUpdatedProperties:(NSMutableSet<RCTApplierBlock> *)applierBlocks
|
|
|
|
parentProperties:(NSDictionary<NSString *, id> *)parentProperties
|
2015-01-30 01:10:49 +00:00
|
|
|
{
|
|
|
|
return parentProperties;
|
|
|
|
}
|
|
|
|
|
2015-11-03 22:45:46 +00:00
|
|
|
- (void)collectUpdatedProperties:(NSMutableSet<RCTApplierBlock> *)applierBlocks
|
2015-11-14 18:25:00 +00:00
|
|
|
parentProperties:(NSDictionary<NSString *, id> *)parentProperties
|
2015-01-30 01:10:49 +00:00
|
|
|
{
|
2015-03-02 19:36:55 +00:00
|
|
|
if (_propagationLifecycle == RCTUpdateLifecycleComputed && [parentProperties isEqualToDictionary:_lastParentProperties]) {
|
2015-01-30 01:10:49 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-03-02 19:36:55 +00:00
|
|
|
_propagationLifecycle = RCTUpdateLifecycleComputed;
|
2015-01-30 01:10:49 +00:00
|
|
|
_lastParentProperties = parentProperties;
|
2015-11-14 18:25:00 +00:00
|
|
|
NSDictionary<NSString *, id> *nextProps = [self processUpdatedProperties:applierBlocks parentProperties:parentProperties];
|
2015-01-30 01:10:49 +00:00
|
|
|
for (RCTShadowView *child in _reactSubviews) {
|
|
|
|
[child collectUpdatedProperties:applierBlocks parentProperties:nextProps];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-31 17:18:37 +00:00
|
|
|
- (void)collectUpdatedFrames:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
|
|
|
|
withFrame:(CGRect)frame
|
|
|
|
hidden:(BOOL)hidden
|
|
|
|
absolutePosition:(CGPoint)absolutePosition
|
|
|
|
{
|
2017-12-20 03:48:22 +00:00
|
|
|
// This is not the core layout method. It is only used by RCTTextShadowView to layout
|
2017-02-28 16:10:34 +00:00
|
|
|
// nested views.
|
|
|
|
|
2016-05-31 17:18:37 +00:00
|
|
|
if (_hidden != hidden) {
|
|
|
|
// The hidden state has changed. Even if the frame hasn't changed, add
|
|
|
|
// this ShadowView to viewsWithNewFrame so the UIManager will process
|
|
|
|
// this ShadowView's UIView and update its hidden state.
|
|
|
|
_hidden = hidden;
|
|
|
|
[viewsWithNewFrame addObject:self];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CGRectEqualToRect(frame, _frame)) {
|
2017-02-21 16:43:34 +00:00
|
|
|
YGNodeStyleSetPositionType(_yogaNode, YGPositionTypeAbsolute);
|
|
|
|
YGNodeStyleSetWidth(_yogaNode, frame.size.width);
|
|
|
|
YGNodeStyleSetHeight(_yogaNode, frame.size.height);
|
|
|
|
YGNodeStyleSetPosition(_yogaNode, YGEdgeLeft, frame.origin.x);
|
|
|
|
YGNodeStyleSetPosition(_yogaNode, YGEdgeTop, frame.origin.y);
|
2016-05-31 17:18:37 +00:00
|
|
|
}
|
|
|
|
|
2017-02-21 16:43:34 +00:00
|
|
|
YGNodeCalculateLayout(_yogaNode, frame.size.width, frame.size.height, YGDirectionInherit);
|
|
|
|
[self applyLayoutNode:_yogaNode viewsWithNewFrame:viewsWithNewFrame absolutePosition:absolutePosition];
|
2016-05-31 17:18:37 +00:00
|
|
|
}
|
|
|
|
|
2015-03-25 02:34:12 +00:00
|
|
|
- (CGRect)measureLayoutRelativeToAncestor:(RCTShadowView *)ancestor
|
2015-01-30 01:10:49 +00:00
|
|
|
{
|
2015-06-01 15:34:09 +00:00
|
|
|
CGPoint offset = CGPointZero;
|
2015-03-25 02:34:12 +00:00
|
|
|
NSInteger depth = 30; // max depth to search
|
|
|
|
RCTShadowView *shadowView = self;
|
|
|
|
while (depth && shadowView && shadowView != ancestor) {
|
2015-06-01 15:34:09 +00:00
|
|
|
offset.x += shadowView.frame.origin.x;
|
|
|
|
offset.y += shadowView.frame.origin.y;
|
2015-01-30 01:10:49 +00:00
|
|
|
shadowView = shadowView->_superview;
|
2015-03-25 02:34:12 +00:00
|
|
|
depth--;
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
if (ancestor != shadowView) {
|
|
|
|
return CGRectNull;
|
|
|
|
}
|
2015-06-01 15:34:09 +00:00
|
|
|
return (CGRect){offset, self.frame.size};
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
|
2016-08-03 11:01:45 +00:00
|
|
|
- (BOOL)viewIsDescendantOf:(RCTShadowView *)ancestor
|
|
|
|
{
|
|
|
|
NSInteger depth = 30; // max depth to search
|
|
|
|
RCTShadowView *shadowView = self;
|
|
|
|
while (depth && shadowView && shadowView != ancestor) {
|
|
|
|
shadowView = shadowView->_superview;
|
|
|
|
depth--;
|
|
|
|
}
|
|
|
|
return ancestor == shadowView;
|
|
|
|
}
|
|
|
|
|
2015-01-30 01:10:49 +00:00
|
|
|
- (instancetype)init
|
|
|
|
{
|
|
|
|
if ((self = [super init])) {
|
2016-12-02 13:47:43 +00:00
|
|
|
_frame = CGRectMake(0, 0, YGUndefined, YGUndefined);
|
2015-01-30 01:10:49 +00:00
|
|
|
|
2015-08-24 10:14:33 +00:00
|
|
|
for (unsigned int ii = 0; ii < META_PROP_COUNT; ii++) {
|
2017-01-11 11:58:03 +00:00
|
|
|
_paddingMetaProps[ii] = YGValueUndefined;
|
|
|
|
_marginMetaProps[ii] = YGValueUndefined;
|
|
|
|
_borderMetaProps[ii] = YGValueUndefined;
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
|
2017-02-01 00:47:11 +00:00
|
|
|
_intrinsicContentSize = CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric);
|
|
|
|
|
2015-01-30 01:10:49 +00:00
|
|
|
_newView = YES;
|
2015-03-02 19:36:55 +00:00
|
|
|
_propagationLifecycle = RCTUpdateLifecycleUninitialized;
|
|
|
|
_textLifecycle = RCTUpdateLifecycleUninitialized;
|
2015-01-30 01:10:49 +00:00
|
|
|
|
|
|
|
_reactSubviews = [NSMutableArray array];
|
|
|
|
|
2017-04-27 19:48:53 +00:00
|
|
|
_yogaNode = YGNodeNewWithConfig([[self class] yogaConfig]);
|
2017-12-19 19:18:00 +00:00
|
|
|
YGNodeSetContext(_yogaNode, (__bridge void *)self);
|
|
|
|
YGNodeSetPrintFunc(_yogaNode, RCTPrint);
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2015-03-25 02:34:12 +00:00
|
|
|
- (BOOL)isReactRootView
|
|
|
|
{
|
|
|
|
return RCTIsReactRootView(self.reactTag);
|
|
|
|
}
|
|
|
|
|
2015-01-30 01:10:49 +00:00
|
|
|
- (void)dealloc
|
|
|
|
{
|
2017-02-21 16:43:34 +00:00
|
|
|
YGNodeFree(_yogaNode);
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
|
2017-06-21 00:09:52 +00:00
|
|
|
- (BOOL)canHaveSubviews
|
|
|
|
{
|
2017-09-07 06:40:19 +00:00
|
|
|
return YES;
|
2017-06-21 00:09:52 +00:00
|
|
|
}
|
|
|
|
|
2017-02-21 16:43:34 +00:00
|
|
|
- (BOOL)isYogaLeafNode
|
2016-07-20 09:49:13 +00:00
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2015-01-30 01:10:49 +00:00
|
|
|
- (void)insertReactSubview:(RCTShadowView *)subview atIndex:(NSInteger)atIndex
|
|
|
|
{
|
2017-09-07 06:40:19 +00:00
|
|
|
RCTAssert(self.canHaveSubviews, @"Attempt to insert subview inside leaf view.");
|
2017-06-21 00:09:52 +00:00
|
|
|
|
2015-01-30 01:10:49 +00:00
|
|
|
[_reactSubviews insertObject:subview atIndex:atIndex];
|
2017-02-21 16:43:34 +00:00
|
|
|
if (![self isYogaLeafNode]) {
|
|
|
|
YGNodeInsertChild(_yogaNode, subview.yogaNode, (uint32_t)atIndex);
|
2016-07-20 20:26:57 +00:00
|
|
|
}
|
2015-01-30 01:10:49 +00:00
|
|
|
subview->_superview = self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)removeReactSubview:(RCTShadowView *)subview
|
|
|
|
{
|
|
|
|
subview->_superview = nil;
|
|
|
|
[_reactSubviews removeObject:subview];
|
2017-02-21 16:43:34 +00:00
|
|
|
if (![self isYogaLeafNode]) {
|
|
|
|
YGNodeRemoveChild(_yogaNode, subview.yogaNode);
|
2016-07-20 20:26:57 +00:00
|
|
|
}
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-03 22:45:46 +00:00
|
|
|
- (NSArray<RCTShadowView *> *)reactSubviews
|
2015-01-30 01:10:49 +00:00
|
|
|
{
|
|
|
|
return _reactSubviews;
|
|
|
|
}
|
|
|
|
|
2015-03-06 17:54:10 +00:00
|
|
|
- (RCTShadowView *)reactSuperview
|
|
|
|
{
|
|
|
|
return _superview;
|
|
|
|
}
|
|
|
|
|
2015-02-06 23:45:28 +00:00
|
|
|
- (NSNumber *)reactTagAtPoint:(CGPoint)point
|
|
|
|
{
|
|
|
|
for (RCTShadowView *shadowView in _reactSubviews) {
|
|
|
|
if (CGRectContainsPoint(shadowView.frame, point)) {
|
|
|
|
CGPoint relativePoint = point;
|
|
|
|
CGPoint origin = shadowView.frame.origin;
|
|
|
|
relativePoint.x -= origin.x;
|
|
|
|
relativePoint.y -= origin.y;
|
|
|
|
return [shadowView reactTagAtPoint:relativePoint];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return self.reactTag;
|
|
|
|
}
|
|
|
|
|
2015-06-15 19:05:04 +00:00
|
|
|
- (NSString *)description
|
|
|
|
{
|
|
|
|
NSString *description = super.description;
|
2015-07-17 10:53:15 +00:00
|
|
|
description = [[description substringToIndex:description.length - 1] stringByAppendingFormat:@"; viewName: %@; reactTag: %@; frame: %@>", self.viewName, self.reactTag, NSStringFromCGRect(self.frame)];
|
|
|
|
return description;
|
2015-06-15 19:05:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)addRecursiveDescriptionToString:(NSMutableString *)string atLevel:(NSUInteger)level
|
|
|
|
{
|
|
|
|
for (NSUInteger i = 0; i < level; i++) {
|
|
|
|
[string appendString:@" | "];
|
|
|
|
}
|
|
|
|
|
|
|
|
[string appendString:self.description];
|
|
|
|
[string appendString:@"\n"];
|
|
|
|
|
|
|
|
for (RCTShadowView *subview in _reactSubviews) {
|
|
|
|
[subview addRecursiveDescriptionToString:string atLevel:level + 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)recursiveDescription
|
|
|
|
{
|
|
|
|
NSMutableString *description = [NSMutableString string];
|
|
|
|
[self addRecursiveDescriptionToString:description atLevel:0];
|
|
|
|
return description;
|
|
|
|
}
|
|
|
|
|
2015-01-30 01:10:49 +00:00
|
|
|
// Margin
|
|
|
|
|
|
|
|
#define RCT_MARGIN_PROPERTY(prop, metaProp) \
|
2017-01-11 11:58:03 +00:00
|
|
|
- (void)setMargin##prop:(YGValue)value \
|
2015-01-30 01:10:49 +00:00
|
|
|
{ \
|
|
|
|
_marginMetaProps[META_PROP_##metaProp] = value; \
|
|
|
|
_recomputeMargin = YES; \
|
|
|
|
} \
|
2017-01-11 11:58:03 +00:00
|
|
|
- (YGValue)margin##prop \
|
2015-01-30 01:10:49 +00:00
|
|
|
{ \
|
|
|
|
return _marginMetaProps[META_PROP_##metaProp]; \
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT_MARGIN_PROPERTY(, ALL)
|
|
|
|
RCT_MARGIN_PROPERTY(Vertical, VERTICAL)
|
|
|
|
RCT_MARGIN_PROPERTY(Horizontal, HORIZONTAL)
|
|
|
|
RCT_MARGIN_PROPERTY(Top, TOP)
|
|
|
|
RCT_MARGIN_PROPERTY(Left, LEFT)
|
|
|
|
RCT_MARGIN_PROPERTY(Bottom, BOTTOM)
|
|
|
|
RCT_MARGIN_PROPERTY(Right, RIGHT)
|
2017-10-19 02:29:46 +00:00
|
|
|
RCT_MARGIN_PROPERTY(Start, START)
|
|
|
|
RCT_MARGIN_PROPERTY(End, END)
|
2015-01-30 01:10:49 +00:00
|
|
|
|
|
|
|
// Padding
|
|
|
|
|
|
|
|
#define RCT_PADDING_PROPERTY(prop, metaProp) \
|
2017-01-11 11:58:03 +00:00
|
|
|
- (void)setPadding##prop:(YGValue)value \
|
2015-01-30 01:10:49 +00:00
|
|
|
{ \
|
|
|
|
_paddingMetaProps[META_PROP_##metaProp] = value; \
|
|
|
|
_recomputePadding = YES; \
|
|
|
|
} \
|
2017-01-11 11:58:03 +00:00
|
|
|
- (YGValue)padding##prop \
|
2015-01-30 01:10:49 +00:00
|
|
|
{ \
|
2015-02-19 01:46:39 +00:00
|
|
|
return _paddingMetaProps[META_PROP_##metaProp]; \
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RCT_PADDING_PROPERTY(, ALL)
|
|
|
|
RCT_PADDING_PROPERTY(Vertical, VERTICAL)
|
|
|
|
RCT_PADDING_PROPERTY(Horizontal, HORIZONTAL)
|
|
|
|
RCT_PADDING_PROPERTY(Top, TOP)
|
|
|
|
RCT_PADDING_PROPERTY(Left, LEFT)
|
|
|
|
RCT_PADDING_PROPERTY(Bottom, BOTTOM)
|
|
|
|
RCT_PADDING_PROPERTY(Right, RIGHT)
|
2017-10-19 02:29:44 +00:00
|
|
|
RCT_PADDING_PROPERTY(Start, START)
|
|
|
|
RCT_PADDING_PROPERTY(End, END)
|
2015-01-30 01:10:49 +00:00
|
|
|
|
|
|
|
// Border
|
|
|
|
|
2017-01-11 11:58:03 +00:00
|
|
|
#define RCT_BORDER_PROPERTY(prop, metaProp) \
|
|
|
|
- (void)setBorder##prop##Width:(float)value \
|
|
|
|
{ \
|
|
|
|
_borderMetaProps[META_PROP_##metaProp].value = value; \
|
|
|
|
_recomputeBorder = YES; \
|
|
|
|
} \
|
|
|
|
- (float)border##prop##Width \
|
|
|
|
{ \
|
|
|
|
return _borderMetaProps[META_PROP_##metaProp].value; \
|
2015-02-19 01:46:39 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 13:20:28 +00:00
|
|
|
RCT_BORDER_PROPERTY(, ALL)
|
2015-02-19 01:46:39 +00:00
|
|
|
RCT_BORDER_PROPERTY(Top, TOP)
|
|
|
|
RCT_BORDER_PROPERTY(Left, LEFT)
|
|
|
|
RCT_BORDER_PROPERTY(Bottom, BOTTOM)
|
|
|
|
RCT_BORDER_PROPERTY(Right, RIGHT)
|
2017-10-19 02:29:42 +00:00
|
|
|
RCT_BORDER_PROPERTY(Start, START)
|
|
|
|
RCT_BORDER_PROPERTY(End, END)
|
2015-02-19 01:46:39 +00:00
|
|
|
|
2015-01-30 01:10:49 +00:00
|
|
|
// Dimensions
|
2016-07-20 15:46:00 +00:00
|
|
|
#define RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp) \
|
2017-01-11 11:58:03 +00:00
|
|
|
- (void)set##setProp:(YGValue)value \
|
2017-03-01 17:12:45 +00:00
|
|
|
{ \
|
|
|
|
RCT_SET_YGVALUE_AUTO(value, YGNodeStyleSet##cssProp, _yogaNode); \
|
|
|
|
} \
|
|
|
|
- (YGValue)getProp \
|
|
|
|
{ \
|
|
|
|
return YGNodeStyleGet##cssProp(_yogaNode); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define RCT_MIN_MAX_DIMENSION_PROPERTY(setProp, getProp, cssProp) \
|
|
|
|
- (void)set##setProp:(YGValue)value \
|
2016-06-15 16:44:34 +00:00
|
|
|
{ \
|
2017-02-21 16:43:34 +00:00
|
|
|
RCT_SET_YGVALUE(value, YGNodeStyleSet##cssProp, _yogaNode); \
|
2016-06-15 16:44:34 +00:00
|
|
|
} \
|
2017-01-11 11:58:03 +00:00
|
|
|
- (YGValue)getProp \
|
2016-06-15 16:44:34 +00:00
|
|
|
{ \
|
2017-02-21 16:43:34 +00:00
|
|
|
return YGNodeStyleGet##cssProp(_yogaNode); \
|
2015-11-17 18:57:00 +00:00
|
|
|
}
|
|
|
|
|
2016-07-20 15:46:00 +00:00
|
|
|
RCT_DIMENSION_PROPERTY(Width, width, Width)
|
|
|
|
RCT_DIMENSION_PROPERTY(Height, height, Height)
|
2017-03-01 17:12:45 +00:00
|
|
|
RCT_MIN_MAX_DIMENSION_PROPERTY(MinWidth, minWidth, MinWidth)
|
|
|
|
RCT_MIN_MAX_DIMENSION_PROPERTY(MinHeight, minHeight, MinHeight)
|
|
|
|
RCT_MIN_MAX_DIMENSION_PROPERTY(MaxWidth, maxWidth, MaxWidth)
|
|
|
|
RCT_MIN_MAX_DIMENSION_PROPERTY(MaxHeight, maxHeight, MaxHeight)
|
2015-01-30 01:10:49 +00:00
|
|
|
|
|
|
|
// Position
|
|
|
|
|
2016-08-15 16:15:10 +00:00
|
|
|
#define RCT_POSITION_PROPERTY(setProp, getProp, edge) \
|
2017-01-11 11:58:03 +00:00
|
|
|
- (void)set##setProp:(YGValue)value \
|
2016-08-15 16:15:10 +00:00
|
|
|
{ \
|
2017-02-21 16:43:34 +00:00
|
|
|
RCT_SET_YGVALUE(value, YGNodeStyleSetPosition, _yogaNode, edge); \
|
2016-08-15 16:15:10 +00:00
|
|
|
} \
|
2017-01-11 11:58:03 +00:00
|
|
|
- (YGValue)getProp \
|
2016-08-15 16:15:10 +00:00
|
|
|
{ \
|
2017-02-21 16:43:34 +00:00
|
|
|
return YGNodeStyleGetPosition(_yogaNode, edge); \
|
2016-08-15 16:15:10 +00:00
|
|
|
}
|
|
|
|
|
2017-10-19 02:29:40 +00:00
|
|
|
|
2016-12-02 13:47:43 +00:00
|
|
|
RCT_POSITION_PROPERTY(Top, top, YGEdgeTop)
|
|
|
|
RCT_POSITION_PROPERTY(Bottom, bottom, YGEdgeBottom)
|
2017-10-19 02:29:40 +00:00
|
|
|
RCT_POSITION_PROPERTY(Start, start, YGEdgeStart)
|
|
|
|
RCT_POSITION_PROPERTY(End, end, YGEdgeEnd)
|
|
|
|
|
|
|
|
- (void)setLeft:(YGValue)value
|
|
|
|
{
|
2017-10-25 03:32:17 +00:00
|
|
|
YGEdge edge = [[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL] ? YGEdgeStart : YGEdgeLeft;
|
2017-10-19 02:29:40 +00:00
|
|
|
RCT_SET_YGVALUE(value, YGNodeStyleSetPosition, _yogaNode, edge);
|
|
|
|
}
|
|
|
|
- (YGValue)left
|
|
|
|
{
|
2017-10-25 03:32:17 +00:00
|
|
|
YGEdge edge = [[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL] ? YGEdgeStart : YGEdgeLeft;
|
2017-10-19 02:29:40 +00:00
|
|
|
return YGNodeStyleGetPosition(_yogaNode, edge);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setRight:(YGValue)value
|
|
|
|
{
|
2017-10-25 03:32:17 +00:00
|
|
|
YGEdge edge = [[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL] ? YGEdgeEnd : YGEdgeRight;
|
2017-10-19 02:29:40 +00:00
|
|
|
RCT_SET_YGVALUE(value, YGNodeStyleSetPosition, _yogaNode, edge);
|
|
|
|
}
|
|
|
|
- (YGValue)right
|
|
|
|
{
|
2017-10-25 03:32:17 +00:00
|
|
|
YGEdge edge = [[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL] ? YGEdgeEnd : YGEdgeRight;
|
2017-10-19 02:29:40 +00:00
|
|
|
return YGNodeStyleGetPosition(_yogaNode, edge);
|
|
|
|
}
|
2015-01-30 01:10:49 +00:00
|
|
|
|
Deprecating/removing `setFrame`, `setLeftTop`, and co.
Summary:
Motivation:
* `RCTShadowView`'s `frame` property actually represents computed layout of the view. We must not use it as a setter for yoga node styles;
* Using `frame` and `setLeftTop` in existing way actually works only for view with absolute positioning, so it is super rare and special case;
* Internally, setting `frame` only make sense to `RootView`, and in that case there we always must not change `origin` we are introducing `setSize` method.
Changes:
* `[-RCTShadowView setFrame:]` was removed, `frame` property is readonly now;
* `[-RCTShadowView setLeftTop:]` was removed; no replacement provided;
* `[-RCTShadowView size]` read-write property was added;
* `[-RCTUIManager setFrame:forView:]` was deprecated, use (just introduced) `setSize:forView:` instead;
* `[-RCTUIManager setSize:forView:]` was added.
If you are still need some of removed methods, you are probably doing something wrong. Consider using `setIntrinsicContentSize`-family methods,
`setSize`-family methods, or (in the worst case) accessing `yogaNode` directly.
Reviewed By: javache
Differential Revision: D4491384
fbshipit-source-id: 56dd84567324c5a86e4c870a41c38322dc1224d2
2017-02-01 20:59:26 +00:00
|
|
|
// Size
|
|
|
|
|
|
|
|
- (CGSize)size
|
2015-01-30 01:10:49 +00:00
|
|
|
{
|
2017-02-21 16:43:34 +00:00
|
|
|
YGValue width = YGNodeStyleGetWidth(_yogaNode);
|
|
|
|
YGValue height = YGNodeStyleGetHeight(_yogaNode);
|
Deprecating/removing `setFrame`, `setLeftTop`, and co.
Summary:
Motivation:
* `RCTShadowView`'s `frame` property actually represents computed layout of the view. We must not use it as a setter for yoga node styles;
* Using `frame` and `setLeftTop` in existing way actually works only for view with absolute positioning, so it is super rare and special case;
* Internally, setting `frame` only make sense to `RootView`, and in that case there we always must not change `origin` we are introducing `setSize` method.
Changes:
* `[-RCTShadowView setFrame:]` was removed, `frame` property is readonly now;
* `[-RCTShadowView setLeftTop:]` was removed; no replacement provided;
* `[-RCTShadowView size]` read-write property was added;
* `[-RCTUIManager setFrame:forView:]` was deprecated, use (just introduced) `setSize:forView:` instead;
* `[-RCTUIManager setSize:forView:]` was added.
If you are still need some of removed methods, you are probably doing something wrong. Consider using `setIntrinsicContentSize`-family methods,
`setSize`-family methods, or (in the worst case) accessing `yogaNode` directly.
Reviewed By: javache
Differential Revision: D4491384
fbshipit-source-id: 56dd84567324c5a86e4c870a41c38322dc1224d2
2017-02-01 20:59:26 +00:00
|
|
|
|
|
|
|
return CGSizeMake(
|
2017-02-14 22:26:13 +00:00
|
|
|
width.unit == YGUnitPoint ? width.value : NAN,
|
|
|
|
height.unit == YGUnitPoint ? height.value : NAN
|
Deprecating/removing `setFrame`, `setLeftTop`, and co.
Summary:
Motivation:
* `RCTShadowView`'s `frame` property actually represents computed layout of the view. We must not use it as a setter for yoga node styles;
* Using `frame` and `setLeftTop` in existing way actually works only for view with absolute positioning, so it is super rare and special case;
* Internally, setting `frame` only make sense to `RootView`, and in that case there we always must not change `origin` we are introducing `setSize` method.
Changes:
* `[-RCTShadowView setFrame:]` was removed, `frame` property is readonly now;
* `[-RCTShadowView setLeftTop:]` was removed; no replacement provided;
* `[-RCTShadowView size]` read-write property was added;
* `[-RCTUIManager setFrame:forView:]` was deprecated, use (just introduced) `setSize:forView:` instead;
* `[-RCTUIManager setSize:forView:]` was added.
If you are still need some of removed methods, you are probably doing something wrong. Consider using `setIntrinsicContentSize`-family methods,
`setSize`-family methods, or (in the worst case) accessing `yogaNode` directly.
Reviewed By: javache
Differential Revision: D4491384
fbshipit-source-id: 56dd84567324c5a86e4c870a41c38322dc1224d2
2017-02-01 20:59:26 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setSize:(CGSize)size
|
|
|
|
{
|
2017-02-21 16:43:34 +00:00
|
|
|
YGNodeStyleSetWidth(_yogaNode, size.width);
|
|
|
|
YGNodeStyleSetHeight(_yogaNode, size.height);
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
|
Deprecating/removing `setFrame`, `setLeftTop`, and co.
Summary:
Motivation:
* `RCTShadowView`'s `frame` property actually represents computed layout of the view. We must not use it as a setter for yoga node styles;
* Using `frame` and `setLeftTop` in existing way actually works only for view with absolute positioning, so it is super rare and special case;
* Internally, setting `frame` only make sense to `RootView`, and in that case there we always must not change `origin` we are introducing `setSize` method.
Changes:
* `[-RCTShadowView setFrame:]` was removed, `frame` property is readonly now;
* `[-RCTShadowView setLeftTop:]` was removed; no replacement provided;
* `[-RCTShadowView size]` read-write property was added;
* `[-RCTUIManager setFrame:forView:]` was deprecated, use (just introduced) `setSize:forView:` instead;
* `[-RCTUIManager setSize:forView:]` was added.
If you are still need some of removed methods, you are probably doing something wrong. Consider using `setIntrinsicContentSize`-family methods,
`setSize`-family methods, or (in the worst case) accessing `yogaNode` directly.
Reviewed By: javache
Differential Revision: D4491384
fbshipit-source-id: 56dd84567324c5a86e4c870a41c38322dc1224d2
2017-02-01 20:59:26 +00:00
|
|
|
// IntrinsicContentSize
|
|
|
|
|
2017-02-01 00:47:11 +00:00
|
|
|
static inline YGSize RCTShadowViewMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode)
|
|
|
|
{
|
|
|
|
RCTShadowView *shadowView = (__bridge RCTShadowView *)YGNodeGetContext(node);
|
|
|
|
|
|
|
|
CGSize intrinsicContentSize = shadowView->_intrinsicContentSize;
|
|
|
|
// Replace `UIViewNoIntrinsicMetric` (which equals `-1`) with zero.
|
|
|
|
intrinsicContentSize.width = MAX(0, intrinsicContentSize.width);
|
|
|
|
intrinsicContentSize.height = MAX(0, intrinsicContentSize.height);
|
|
|
|
|
|
|
|
YGSize result;
|
|
|
|
|
|
|
|
switch (widthMode) {
|
|
|
|
case YGMeasureModeUndefined:
|
|
|
|
result.width = intrinsicContentSize.width;
|
|
|
|
break;
|
|
|
|
case YGMeasureModeExactly:
|
|
|
|
result.width = width;
|
|
|
|
break;
|
|
|
|
case YGMeasureModeAtMost:
|
|
|
|
result.width = MIN(width, intrinsicContentSize.width);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (heightMode) {
|
|
|
|
case YGMeasureModeUndefined:
|
|
|
|
result.height = intrinsicContentSize.height;
|
|
|
|
break;
|
|
|
|
case YGMeasureModeExactly:
|
|
|
|
result.height = height;
|
|
|
|
break;
|
|
|
|
case YGMeasureModeAtMost:
|
|
|
|
result.height = MIN(height, intrinsicContentSize.height);
|
|
|
|
break;
|
2016-03-01 18:13:22 +00:00
|
|
|
}
|
2017-02-01 00:47:11 +00:00
|
|
|
|
|
|
|
return result;
|
2016-03-01 18:13:22 +00:00
|
|
|
}
|
|
|
|
|
2017-02-01 00:47:11 +00:00
|
|
|
- (void)setIntrinsicContentSize:(CGSize)intrinsicContentSize
|
2016-03-01 18:13:22 +00:00
|
|
|
{
|
2017-02-01 00:47:11 +00:00
|
|
|
if (CGSizeEqualToSize(_intrinsicContentSize, intrinsicContentSize)) {
|
|
|
|
return;
|
2016-03-01 18:13:22 +00:00
|
|
|
}
|
2017-02-01 00:47:11 +00:00
|
|
|
|
|
|
|
_intrinsicContentSize = intrinsicContentSize;
|
|
|
|
|
|
|
|
if (CGSizeEqualToSize(_intrinsicContentSize, CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric))) {
|
2017-02-21 16:43:34 +00:00
|
|
|
YGNodeSetMeasureFunc(_yogaNode, NULL);
|
2017-02-01 00:47:11 +00:00
|
|
|
} else {
|
2017-02-21 16:43:34 +00:00
|
|
|
YGNodeSetMeasureFunc(_yogaNode, RCTShadowViewMeasure);
|
2017-02-01 00:47:11 +00:00
|
|
|
}
|
|
|
|
|
2017-02-21 16:43:34 +00:00
|
|
|
YGNodeMarkDirty(_yogaNode);
|
2016-03-01 18:13:22 +00:00
|
|
|
}
|
|
|
|
|
2017-10-09 17:35:13 +00:00
|
|
|
// Local Data
|
|
|
|
|
|
|
|
- (void)setLocalData:(__unused NSObject *)localData
|
|
|
|
{
|
|
|
|
// Do nothing by default.
|
|
|
|
}
|
|
|
|
|
2015-01-30 01:10:49 +00:00
|
|
|
// Flex
|
|
|
|
|
2017-01-11 11:58:03 +00:00
|
|
|
- (void)setFlexBasis:(YGValue)value
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 13:20:37 +00:00
|
|
|
{
|
2017-03-01 17:12:45 +00:00
|
|
|
RCT_SET_YGVALUE_AUTO(value, YGNodeStyleSetFlexBasis, _yogaNode);
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 13:20:37 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 11:58:03 +00:00
|
|
|
- (YGValue)flexBasis
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 13:20:37 +00:00
|
|
|
{
|
2017-02-21 16:43:34 +00:00
|
|
|
return YGNodeStyleGetFlexBasis(_yogaNode);
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 13:20:37 +00:00
|
|
|
}
|
|
|
|
|
2015-01-30 01:10:49 +00:00
|
|
|
#define RCT_STYLE_PROPERTY(setProp, getProp, cssProp, type) \
|
|
|
|
- (void)set##setProp:(type)value \
|
|
|
|
{ \
|
2017-02-21 16:43:34 +00:00
|
|
|
YGNodeStyleSet##cssProp(_yogaNode, value); \
|
2015-01-30 01:10:49 +00:00
|
|
|
} \
|
|
|
|
- (type)getProp \
|
|
|
|
{ \
|
2017-02-21 16:43:34 +00:00
|
|
|
return YGNodeStyleGet##cssProp(_yogaNode); \
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
|
2017-03-13 12:58:09 +00:00
|
|
|
RCT_STYLE_PROPERTY(Flex, flex, Flex, float)
|
2016-10-26 20:12:26 +00:00
|
|
|
RCT_STYLE_PROPERTY(FlexGrow, flexGrow, FlexGrow, float)
|
|
|
|
RCT_STYLE_PROPERTY(FlexShrink, flexShrink, FlexShrink, float)
|
2016-12-02 13:47:43 +00:00
|
|
|
RCT_STYLE_PROPERTY(FlexDirection, flexDirection, FlexDirection, YGFlexDirection)
|
|
|
|
RCT_STYLE_PROPERTY(JustifyContent, justifyContent, JustifyContent, YGJustify)
|
|
|
|
RCT_STYLE_PROPERTY(AlignSelf, alignSelf, AlignSelf, YGAlign)
|
|
|
|
RCT_STYLE_PROPERTY(AlignItems, alignItems, AlignItems, YGAlign)
|
Expose alignContent to react native
Summary:
This diff adds alignContent (https://developer.mozilla.org/en-US/docs/Web/CSS/align-content) support to React Native. This enables aligning the lines of multi-line content. See below playground for example usage.
```
class Playground extends React.Component {
render() {
return (
<View style={{width: '100%', height: '100%', flexDirection: 'row', backgroundColor: 'white', flexWrap: 'wrap', alignContent: 'space-between'}}>
<View style={{width: 100, height: 100, marginLeft: 10, marginTop: 10, backgroundColor: 'red'}}/>
<View style={{width: 100, height: 100, marginLeft: 10, marginTop: 10, backgroundColor: 'red'}}/>
<View style={{width: 100, height: 100, marginLeft: 10, marginTop: 10, backgroundColor: 'red'}}/>
<View style={{width: 100, height: 100, marginLeft: 10, marginTop: 10, backgroundColor: 'red'}}/>
<View style={{width: 100, height: 100, marginLeft: 10, marginTop: 10, backgroundColor: 'red'}}/>
<View style={{width: 100, height: 100, marginLeft: 10, marginTop: 10, backgroundColor: 'red'}}/>
<View style={{width: 100, height: 100, marginLeft: 10, marginTop: 10, backgroundColor: 'red'}}/>
</View>
);
}
}
```
Reviewed By: astreet
Differential Revision: D4611803
fbshipit-source-id: ae7f6b4b7e9f4bc78d2502da948214294aad4dd2
2017-03-01 17:12:48 +00:00
|
|
|
RCT_STYLE_PROPERTY(AlignContent, alignContent, AlignContent, YGAlign)
|
2016-12-02 13:47:43 +00:00
|
|
|
RCT_STYLE_PROPERTY(Position, position, PositionType, YGPositionType)
|
|
|
|
RCT_STYLE_PROPERTY(FlexWrap, flexWrap, FlexWrap, YGWrap)
|
|
|
|
RCT_STYLE_PROPERTY(Overflow, overflow, Overflow, YGOverflow)
|
2017-03-01 17:12:50 +00:00
|
|
|
RCT_STYLE_PROPERTY(Display, display, Display, YGDisplay)
|
2017-02-07 04:58:23 +00:00
|
|
|
RCT_STYLE_PROPERTY(Direction, direction, Direction, YGDirection)
|
2016-11-23 15:32:08 +00:00
|
|
|
RCT_STYLE_PROPERTY(AspectRatio, aspectRatio, AspectRatio, float)
|
2015-01-30 01:10:49 +00:00
|
|
|
|
2016-06-07 07:08:16 +00:00
|
|
|
- (void)didUpdateReactSubviews
|
|
|
|
{
|
|
|
|
// Does nothing by default
|
|
|
|
}
|
|
|
|
|
2015-12-02 15:08:29 +00:00
|
|
|
- (void)didSetProps:(__unused NSArray<NSString *> *)changedProps
|
2015-02-19 01:39:09 +00:00
|
|
|
{
|
|
|
|
if (_recomputePadding) {
|
2017-02-21 16:43:34 +00:00
|
|
|
RCTProcessMetaPropsPadding(_paddingMetaProps, _yogaNode);
|
2015-02-19 01:39:09 +00:00
|
|
|
}
|
|
|
|
if (_recomputeMargin) {
|
2017-02-21 16:43:34 +00:00
|
|
|
RCTProcessMetaPropsMargin(_marginMetaProps, _yogaNode);
|
2015-02-19 01:39:09 +00:00
|
|
|
}
|
2015-07-30 13:20:28 +00:00
|
|
|
if (_recomputeBorder) {
|
2017-02-21 16:43:34 +00:00
|
|
|
RCTProcessMetaPropsBorder(_borderMetaProps, _yogaNode);
|
2015-07-30 13:20:28 +00:00
|
|
|
}
|
2015-02-19 01:39:09 +00:00
|
|
|
_recomputeMargin = NO;
|
|
|
|
_recomputePadding = NO;
|
2015-07-30 13:20:28 +00:00
|
|
|
_recomputeBorder = NO;
|
2015-02-19 01:39:09 +00:00
|
|
|
}
|
|
|
|
|
2015-01-30 01:10:49 +00:00
|
|
|
@end
|