RCTShadowView.m 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #import "RCTShadowView.h"
  8. #import "RCTConvert.h"
  9. #import "RCTI18nUtil.h"
  10. #import "RCTLayout.h"
  11. #import "RCTLog.h"
  12. #import "RCTShadowView+Layout.h"
  13. #import "RCTUtils.h"
  14. #import "UIView+Private.h"
  15. #import "UIView+React.h"
  16. typedef void (^RCTActionBlock)(RCTShadowView *shadowViewSelf, id value);
  17. typedef void (^RCTResetActionBlock)(RCTShadowView *shadowViewSelf);
  18. typedef NS_ENUM(unsigned int, meta_prop_t) {
  19. META_PROP_LEFT,
  20. META_PROP_TOP,
  21. META_PROP_RIGHT,
  22. META_PROP_BOTTOM,
  23. META_PROP_START,
  24. META_PROP_END,
  25. META_PROP_HORIZONTAL,
  26. META_PROP_VERTICAL,
  27. META_PROP_ALL,
  28. META_PROP_COUNT,
  29. };
  30. @implementation RCTShadowView {
  31. NSDictionary *_lastParentProperties;
  32. NSMutableArray<RCTShadowView *> *_reactSubviews;
  33. BOOL _recomputePadding;
  34. BOOL _recomputeMargin;
  35. BOOL _recomputeBorder;
  36. YGValue _paddingMetaProps[META_PROP_COUNT];
  37. YGValue _marginMetaProps[META_PROP_COUNT];
  38. YGValue _borderMetaProps[META_PROP_COUNT];
  39. }
  40. + (YGConfigRef)yogaConfig
  41. {
  42. static YGConfigRef yogaConfig;
  43. static dispatch_once_t onceToken;
  44. dispatch_once(&onceToken, ^{
  45. yogaConfig = YGConfigNew();
  46. YGConfigSetPointScaleFactor(yogaConfig, RCTScreenScale());
  47. YGConfigSetUseLegacyStretchBehaviour(yogaConfig, true);
  48. });
  49. return yogaConfig;
  50. }
  51. @synthesize reactTag = _reactTag;
  52. @synthesize rootTag = _rootTag;
  53. // YogaNode API
  54. static void RCTPrint(YGNodeRef node)
  55. {
  56. RCTShadowView *shadowView = (__bridge RCTShadowView *)YGNodeGetContext(node);
  57. printf("%s(%lld), ", shadowView.viewName.UTF8String, (long long)shadowView.reactTag.integerValue);
  58. }
  59. #define RCT_SET_YGVALUE(ygvalue, setter, ...) \
  60. switch (ygvalue.unit) { \
  61. case YGUnitAuto: \
  62. case YGUnitUndefined: \
  63. setter(__VA_ARGS__, YGUndefined); \
  64. break; \
  65. case YGUnitPoint: \
  66. setter(__VA_ARGS__, ygvalue.value); \
  67. break; \
  68. case YGUnitPercent: \
  69. setter##Percent(__VA_ARGS__, ygvalue.value); \
  70. break; \
  71. }
  72. #define RCT_SET_YGVALUE_AUTO(ygvalue, setter, ...) \
  73. switch (ygvalue.unit) { \
  74. case YGUnitAuto: \
  75. setter##Auto(__VA_ARGS__); \
  76. break; \
  77. case YGUnitUndefined: \
  78. setter(__VA_ARGS__, YGUndefined); \
  79. break; \
  80. case YGUnitPoint: \
  81. setter(__VA_ARGS__, ygvalue.value); \
  82. break; \
  83. case YGUnitPercent: \
  84. setter##Percent(__VA_ARGS__, ygvalue.value); \
  85. break; \
  86. }
  87. static void RCTProcessMetaPropsPadding(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node)
  88. {
  89. if (![[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL]) {
  90. RCT_SET_YGVALUE(metaProps[META_PROP_START], YGNodeStyleSetPadding, node, YGEdgeStart);
  91. RCT_SET_YGVALUE(metaProps[META_PROP_END], YGNodeStyleSetPadding, node, YGEdgeEnd);
  92. RCT_SET_YGVALUE(metaProps[META_PROP_LEFT], YGNodeStyleSetPadding, node, YGEdgeLeft);
  93. RCT_SET_YGVALUE(metaProps[META_PROP_RIGHT], YGNodeStyleSetPadding, node, YGEdgeRight);
  94. } else {
  95. YGValue start =
  96. metaProps[META_PROP_START].unit == YGUnitUndefined ? metaProps[META_PROP_LEFT] : metaProps[META_PROP_START];
  97. YGValue end =
  98. metaProps[META_PROP_END].unit == YGUnitUndefined ? metaProps[META_PROP_RIGHT] : metaProps[META_PROP_END];
  99. RCT_SET_YGVALUE(start, YGNodeStyleSetPadding, node, YGEdgeStart);
  100. RCT_SET_YGVALUE(end, YGNodeStyleSetPadding, node, YGEdgeEnd);
  101. }
  102. RCT_SET_YGVALUE(metaProps[META_PROP_TOP], YGNodeStyleSetPadding, node, YGEdgeTop);
  103. RCT_SET_YGVALUE(metaProps[META_PROP_BOTTOM], YGNodeStyleSetPadding, node, YGEdgeBottom);
  104. RCT_SET_YGVALUE(metaProps[META_PROP_HORIZONTAL], YGNodeStyleSetPadding, node, YGEdgeHorizontal);
  105. RCT_SET_YGVALUE(metaProps[META_PROP_VERTICAL], YGNodeStyleSetPadding, node, YGEdgeVertical);
  106. RCT_SET_YGVALUE(metaProps[META_PROP_ALL], YGNodeStyleSetPadding, node, YGEdgeAll);
  107. }
  108. static void RCTProcessMetaPropsMargin(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node)
  109. {
  110. if (![[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL]) {
  111. RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_START], YGNodeStyleSetMargin, node, YGEdgeStart);
  112. RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_END], YGNodeStyleSetMargin, node, YGEdgeEnd);
  113. RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_LEFT], YGNodeStyleSetMargin, node, YGEdgeLeft);
  114. RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_RIGHT], YGNodeStyleSetMargin, node, YGEdgeRight);
  115. } else {
  116. YGValue start =
  117. metaProps[META_PROP_START].unit == YGUnitUndefined ? metaProps[META_PROP_LEFT] : metaProps[META_PROP_START];
  118. YGValue end =
  119. metaProps[META_PROP_END].unit == YGUnitUndefined ? metaProps[META_PROP_RIGHT] : metaProps[META_PROP_END];
  120. RCT_SET_YGVALUE_AUTO(start, YGNodeStyleSetMargin, node, YGEdgeStart);
  121. RCT_SET_YGVALUE_AUTO(end, YGNodeStyleSetMargin, node, YGEdgeEnd);
  122. }
  123. RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_TOP], YGNodeStyleSetMargin, node, YGEdgeTop);
  124. RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_BOTTOM], YGNodeStyleSetMargin, node, YGEdgeBottom);
  125. RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_HORIZONTAL], YGNodeStyleSetMargin, node, YGEdgeHorizontal);
  126. RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_VERTICAL], YGNodeStyleSetMargin, node, YGEdgeVertical);
  127. RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_ALL], YGNodeStyleSetMargin, node, YGEdgeAll);
  128. }
  129. static void RCTProcessMetaPropsBorder(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node)
  130. {
  131. if (![[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL]) {
  132. YGNodeStyleSetBorder(node, YGEdgeStart, metaProps[META_PROP_START].value);
  133. YGNodeStyleSetBorder(node, YGEdgeEnd, metaProps[META_PROP_END].value);
  134. YGNodeStyleSetBorder(node, YGEdgeLeft, metaProps[META_PROP_LEFT].value);
  135. YGNodeStyleSetBorder(node, YGEdgeRight, metaProps[META_PROP_RIGHT].value);
  136. } else {
  137. const float start = YGFloatIsUndefined(metaProps[META_PROP_START].value) ? metaProps[META_PROP_LEFT].value
  138. : metaProps[META_PROP_START].value;
  139. const float end = YGFloatIsUndefined(metaProps[META_PROP_END].value) ? metaProps[META_PROP_RIGHT].value
  140. : metaProps[META_PROP_END].value;
  141. YGNodeStyleSetBorder(node, YGEdgeStart, start);
  142. YGNodeStyleSetBorder(node, YGEdgeEnd, end);
  143. }
  144. YGNodeStyleSetBorder(node, YGEdgeTop, metaProps[META_PROP_TOP].value);
  145. YGNodeStyleSetBorder(node, YGEdgeBottom, metaProps[META_PROP_BOTTOM].value);
  146. YGNodeStyleSetBorder(node, YGEdgeHorizontal, metaProps[META_PROP_HORIZONTAL].value);
  147. YGNodeStyleSetBorder(node, YGEdgeVertical, metaProps[META_PROP_VERTICAL].value);
  148. YGNodeStyleSetBorder(node, YGEdgeAll, metaProps[META_PROP_ALL].value);
  149. }
  150. - (CGRect)measureLayoutRelativeToAncestor:(RCTShadowView *)ancestor
  151. {
  152. CGPoint offset = CGPointZero;
  153. RCTShadowView *shadowView = self;
  154. while (shadowView && shadowView != ancestor) {
  155. offset.x += shadowView.layoutMetrics.frame.origin.x;
  156. offset.y += shadowView.layoutMetrics.frame.origin.y;
  157. shadowView = shadowView->_superview;
  158. }
  159. if (ancestor != shadowView) {
  160. return CGRectNull;
  161. }
  162. return (CGRect){offset, self.layoutMetrics.frame.size};
  163. }
  164. - (BOOL)viewIsDescendantOf:(RCTShadowView *)ancestor
  165. {
  166. RCTShadowView *shadowView = self;
  167. while (shadowView && shadowView != ancestor) {
  168. shadowView = shadowView->_superview;
  169. }
  170. return ancestor == shadowView;
  171. }
  172. - (instancetype)init
  173. {
  174. if (self = [super init]) {
  175. for (unsigned int ii = 0; ii < META_PROP_COUNT; ii++) {
  176. _paddingMetaProps[ii] = YGValueUndefined;
  177. _marginMetaProps[ii] = YGValueUndefined;
  178. _borderMetaProps[ii] = YGValueUndefined;
  179. }
  180. _intrinsicContentSize = CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric);
  181. _newView = YES;
  182. _reactSubviews = [NSMutableArray array];
  183. _yogaNode = YGNodeNewWithConfig([[self class] yogaConfig]);
  184. YGNodeSetContext(_yogaNode, (__bridge void *)self);
  185. YGNodeSetPrintFunc(_yogaNode, RCTPrint);
  186. }
  187. return self;
  188. }
  189. - (BOOL)isReactRootView
  190. {
  191. return RCTIsReactRootView(self.reactTag);
  192. }
  193. - (void)dealloc
  194. {
  195. YGNodeFree(_yogaNode);
  196. }
  197. - (BOOL)canHaveSubviews
  198. {
  199. return YES;
  200. }
  201. - (BOOL)isYogaLeafNode
  202. {
  203. return NO;
  204. }
  205. - (void)insertReactSubview:(RCTShadowView *)subview atIndex:(NSInteger)atIndex
  206. {
  207. RCTAssert(self.canHaveSubviews, @"Attempt to insert subview inside leaf view.");
  208. [_reactSubviews insertObject:subview atIndex:atIndex];
  209. if (![self isYogaLeafNode]) {
  210. YGNodeInsertChild(_yogaNode, subview.yogaNode, (uint32_t)atIndex);
  211. }
  212. subview->_superview = self;
  213. }
  214. - (void)removeReactSubview:(RCTShadowView *)subview
  215. {
  216. subview->_superview = nil;
  217. [_reactSubviews removeObject:subview];
  218. if (![self isYogaLeafNode]) {
  219. YGNodeRemoveChild(_yogaNode, subview.yogaNode);
  220. }
  221. }
  222. - (NSArray<RCTShadowView *> *)reactSubviews
  223. {
  224. return _reactSubviews;
  225. }
  226. - (RCTShadowView *)reactSuperview
  227. {
  228. return _superview;
  229. }
  230. #pragma mark - Layout
  231. - (void)layoutWithMinimumSize:(CGSize)minimumSize
  232. maximumSize:(CGSize)maximumSize
  233. layoutDirection:(UIUserInterfaceLayoutDirection)layoutDirection
  234. layoutContext:(RCTLayoutContext)layoutContext
  235. {
  236. YGNodeRef yogaNode = _yogaNode;
  237. CGSize oldMinimumSize = (CGSize){RCTCoreGraphicsFloatFromYogaValue(YGNodeStyleGetMinWidth(yogaNode), 0.0),
  238. RCTCoreGraphicsFloatFromYogaValue(YGNodeStyleGetMinHeight(yogaNode), 0.0)};
  239. if (!CGSizeEqualToSize(oldMinimumSize, minimumSize)) {
  240. YGNodeStyleSetMinWidth(yogaNode, RCTYogaFloatFromCoreGraphicsFloat(minimumSize.width));
  241. YGNodeStyleSetMinHeight(yogaNode, RCTYogaFloatFromCoreGraphicsFloat(minimumSize.height));
  242. }
  243. YGNodeCalculateLayout(
  244. yogaNode,
  245. RCTYogaFloatFromCoreGraphicsFloat(maximumSize.width),
  246. RCTYogaFloatFromCoreGraphicsFloat(maximumSize.height),
  247. RCTYogaLayoutDirectionFromUIKitLayoutDirection(layoutDirection));
  248. RCTAssert(!YGNodeIsDirty(yogaNode), @"Attempt to get layout metrics from dirtied Yoga node.");
  249. if (!YGNodeGetHasNewLayout(yogaNode)) {
  250. return;
  251. }
  252. YGNodeSetHasNewLayout(yogaNode, false);
  253. RCTLayoutMetrics layoutMetrics = RCTLayoutMetricsFromYogaNode(yogaNode);
  254. layoutContext.absolutePosition.x += layoutMetrics.frame.origin.x;
  255. layoutContext.absolutePosition.y += layoutMetrics.frame.origin.y;
  256. [self layoutWithMetrics:layoutMetrics layoutContext:layoutContext];
  257. [self layoutSubviewsWithContext:layoutContext];
  258. }
  259. - (void)layoutWithMetrics:(RCTLayoutMetrics)layoutMetrics layoutContext:(RCTLayoutContext)layoutContext
  260. {
  261. if (!RCTLayoutMetricsEqualToLayoutMetrics(self.layoutMetrics, layoutMetrics)) {
  262. self.layoutMetrics = layoutMetrics;
  263. [layoutContext.affectedShadowViews addObject:self];
  264. }
  265. }
  266. - (void)layoutSubviewsWithContext:(RCTLayoutContext)layoutContext
  267. {
  268. RCTLayoutMetrics layoutMetrics = self.layoutMetrics;
  269. if (layoutMetrics.displayType == RCTDisplayTypeNone) {
  270. return;
  271. }
  272. for (RCTShadowView *childShadowView in _reactSubviews) {
  273. YGNodeRef childYogaNode = childShadowView.yogaNode;
  274. RCTAssert(!YGNodeIsDirty(childYogaNode), @"Attempt to get layout metrics from dirtied Yoga node.");
  275. if (!YGNodeGetHasNewLayout(childYogaNode)) {
  276. continue;
  277. }
  278. YGNodeSetHasNewLayout(childYogaNode, false);
  279. RCTLayoutMetrics childLayoutMetrics = RCTLayoutMetricsFromYogaNode(childYogaNode);
  280. layoutContext.absolutePosition.x += childLayoutMetrics.frame.origin.x;
  281. layoutContext.absolutePosition.y += childLayoutMetrics.frame.origin.y;
  282. [childShadowView layoutWithMetrics:childLayoutMetrics layoutContext:layoutContext];
  283. // Recursive call.
  284. [childShadowView layoutSubviewsWithContext:layoutContext];
  285. }
  286. }
  287. - (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize
  288. {
  289. YGNodeRef clonedYogaNode = YGNodeClone(self.yogaNode);
  290. YGNodeRef constraintYogaNode = YGNodeNewWithConfig([[self class] yogaConfig]);
  291. YGNodeInsertChild(constraintYogaNode, clonedYogaNode, 0);
  292. YGNodeStyleSetMinWidth(constraintYogaNode, RCTYogaFloatFromCoreGraphicsFloat(minimumSize.width));
  293. YGNodeStyleSetMinHeight(constraintYogaNode, RCTYogaFloatFromCoreGraphicsFloat(minimumSize.height));
  294. YGNodeStyleSetMaxWidth(constraintYogaNode, RCTYogaFloatFromCoreGraphicsFloat(maximumSize.width));
  295. YGNodeStyleSetMaxHeight(constraintYogaNode, RCTYogaFloatFromCoreGraphicsFloat(maximumSize.height));
  296. YGNodeCalculateLayout(
  297. constraintYogaNode,
  298. YGUndefined,
  299. YGUndefined,
  300. RCTYogaLayoutDirectionFromUIKitLayoutDirection(self.layoutMetrics.layoutDirection));
  301. CGSize measuredSize = (CGSize){
  302. RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetWidth(constraintYogaNode)),
  303. RCTCoreGraphicsFloatFromYogaFloat(YGNodeLayoutGetHeight(constraintYogaNode)),
  304. };
  305. YGNodeRemoveChild(constraintYogaNode, clonedYogaNode);
  306. YGNodeFree(constraintYogaNode);
  307. YGNodeFree(clonedYogaNode);
  308. return measuredSize;
  309. }
  310. - (NSNumber *)reactTagAtPoint:(CGPoint)point
  311. {
  312. for (RCTShadowView *shadowView in _reactSubviews) {
  313. if (CGRectContainsPoint(shadowView.layoutMetrics.frame, point)) {
  314. CGPoint relativePoint = point;
  315. CGPoint origin = shadowView.layoutMetrics.frame.origin;
  316. relativePoint.x -= origin.x;
  317. relativePoint.y -= origin.y;
  318. return [shadowView reactTagAtPoint:relativePoint];
  319. }
  320. }
  321. return self.reactTag;
  322. }
  323. - (NSString *)description
  324. {
  325. NSString *description = super.description;
  326. description = [[description substringToIndex:description.length - 1]
  327. stringByAppendingFormat:@"; viewName: %@; reactTag: %@; frame: %@>",
  328. self.viewName,
  329. self.reactTag,
  330. NSStringFromCGRect(self.layoutMetrics.frame)];
  331. return description;
  332. }
  333. - (void)addRecursiveDescriptionToString:(NSMutableString *)string atLevel:(NSUInteger)level
  334. {
  335. for (NSUInteger i = 0; i < level; i++) {
  336. [string appendString:@" | "];
  337. }
  338. [string appendString:self.description];
  339. [string appendString:@"\n"];
  340. for (RCTShadowView *subview in _reactSubviews) {
  341. [subview addRecursiveDescriptionToString:string atLevel:level + 1];
  342. }
  343. }
  344. - (NSString *)recursiveDescription
  345. {
  346. NSMutableString *description = [NSMutableString string];
  347. [self addRecursiveDescriptionToString:description atLevel:0];
  348. return description;
  349. }
  350. // Margin
  351. #define RCT_MARGIN_PROPERTY(prop, metaProp) \
  352. -(void)setMargin##prop : (YGValue)value \
  353. { \
  354. _marginMetaProps[META_PROP_##metaProp] = value; \
  355. _recomputeMargin = YES; \
  356. } \
  357. -(YGValue)margin##prop \
  358. { \
  359. return _marginMetaProps[META_PROP_##metaProp]; \
  360. }
  361. RCT_MARGIN_PROPERTY(, ALL)
  362. RCT_MARGIN_PROPERTY(Vertical, VERTICAL)
  363. RCT_MARGIN_PROPERTY(Horizontal, HORIZONTAL)
  364. RCT_MARGIN_PROPERTY(Top, TOP)
  365. RCT_MARGIN_PROPERTY(Left, LEFT)
  366. RCT_MARGIN_PROPERTY(Bottom, BOTTOM)
  367. RCT_MARGIN_PROPERTY(Right, RIGHT)
  368. RCT_MARGIN_PROPERTY(Start, START)
  369. RCT_MARGIN_PROPERTY(End, END)
  370. // Padding
  371. #define RCT_PADDING_PROPERTY(prop, metaProp) \
  372. -(void)setPadding##prop : (YGValue)value \
  373. { \
  374. _paddingMetaProps[META_PROP_##metaProp] = value; \
  375. _recomputePadding = YES; \
  376. } \
  377. -(YGValue)padding##prop \
  378. { \
  379. return _paddingMetaProps[META_PROP_##metaProp]; \
  380. }
  381. RCT_PADDING_PROPERTY(, ALL)
  382. RCT_PADDING_PROPERTY(Vertical, VERTICAL)
  383. RCT_PADDING_PROPERTY(Horizontal, HORIZONTAL)
  384. RCT_PADDING_PROPERTY(Top, TOP)
  385. RCT_PADDING_PROPERTY(Left, LEFT)
  386. RCT_PADDING_PROPERTY(Bottom, BOTTOM)
  387. RCT_PADDING_PROPERTY(Right, RIGHT)
  388. RCT_PADDING_PROPERTY(Start, START)
  389. RCT_PADDING_PROPERTY(End, END)
  390. // Border
  391. #define RCT_BORDER_PROPERTY(prop, metaProp) \
  392. -(void)setBorder##prop##Width : (float)value \
  393. { \
  394. _borderMetaProps[META_PROP_##metaProp].value = value; \
  395. _recomputeBorder = YES; \
  396. } \
  397. -(float)border##prop##Width \
  398. { \
  399. return _borderMetaProps[META_PROP_##metaProp].value; \
  400. }
  401. RCT_BORDER_PROPERTY(, ALL)
  402. RCT_BORDER_PROPERTY(Top, TOP)
  403. RCT_BORDER_PROPERTY(Left, LEFT)
  404. RCT_BORDER_PROPERTY(Bottom, BOTTOM)
  405. RCT_BORDER_PROPERTY(Right, RIGHT)
  406. RCT_BORDER_PROPERTY(Start, START)
  407. RCT_BORDER_PROPERTY(End, END)
  408. // Dimensions
  409. #define RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp) \
  410. -(void)set##setProp : (YGValue)value \
  411. { \
  412. RCT_SET_YGVALUE_AUTO(value, YGNodeStyleSet##cssProp, _yogaNode); \
  413. } \
  414. -(YGValue)getProp \
  415. { \
  416. return YGNodeStyleGet##cssProp(_yogaNode); \
  417. }
  418. #define RCT_MIN_MAX_DIMENSION_PROPERTY(setProp, getProp, cssProp) \
  419. -(void)set##setProp : (YGValue)value \
  420. { \
  421. RCT_SET_YGVALUE(value, YGNodeStyleSet##cssProp, _yogaNode); \
  422. } \
  423. -(YGValue)getProp \
  424. { \
  425. return YGNodeStyleGet##cssProp(_yogaNode); \
  426. }
  427. RCT_DIMENSION_PROPERTY(Width, width, Width)
  428. RCT_DIMENSION_PROPERTY(Height, height, Height)
  429. RCT_MIN_MAX_DIMENSION_PROPERTY(MinWidth, minWidth, MinWidth)
  430. RCT_MIN_MAX_DIMENSION_PROPERTY(MinHeight, minHeight, MinHeight)
  431. RCT_MIN_MAX_DIMENSION_PROPERTY(MaxWidth, maxWidth, MaxWidth)
  432. RCT_MIN_MAX_DIMENSION_PROPERTY(MaxHeight, maxHeight, MaxHeight)
  433. // Position
  434. #define RCT_POSITION_PROPERTY(setProp, getProp, edge) \
  435. -(void)set##setProp : (YGValue)value \
  436. { \
  437. RCT_SET_YGVALUE(value, YGNodeStyleSetPosition, _yogaNode, edge); \
  438. } \
  439. -(YGValue)getProp \
  440. { \
  441. return YGNodeStyleGetPosition(_yogaNode, edge); \
  442. }
  443. RCT_POSITION_PROPERTY(Top, top, YGEdgeTop)
  444. RCT_POSITION_PROPERTY(Bottom, bottom, YGEdgeBottom)
  445. RCT_POSITION_PROPERTY(Start, start, YGEdgeStart)
  446. RCT_POSITION_PROPERTY(End, end, YGEdgeEnd)
  447. - (void)setLeft:(YGValue)value
  448. {
  449. YGEdge edge = [[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL] ? YGEdgeStart : YGEdgeLeft;
  450. RCT_SET_YGVALUE(value, YGNodeStyleSetPosition, _yogaNode, edge);
  451. }
  452. - (YGValue)left
  453. {
  454. YGEdge edge = [[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL] ? YGEdgeStart : YGEdgeLeft;
  455. return YGNodeStyleGetPosition(_yogaNode, edge);
  456. }
  457. - (void)setRight:(YGValue)value
  458. {
  459. YGEdge edge = [[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL] ? YGEdgeEnd : YGEdgeRight;
  460. RCT_SET_YGVALUE(value, YGNodeStyleSetPosition, _yogaNode, edge);
  461. }
  462. - (YGValue)right
  463. {
  464. YGEdge edge = [[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL] ? YGEdgeEnd : YGEdgeRight;
  465. return YGNodeStyleGetPosition(_yogaNode, edge);
  466. }
  467. // Size
  468. - (CGSize)size
  469. {
  470. YGValue width = YGNodeStyleGetWidth(_yogaNode);
  471. YGValue height = YGNodeStyleGetHeight(_yogaNode);
  472. return CGSizeMake(width.unit == YGUnitPoint ? width.value : NAN, height.unit == YGUnitPoint ? height.value : NAN);
  473. }
  474. - (void)setSize:(CGSize)size
  475. {
  476. YGNodeStyleSetWidth(_yogaNode, size.width);
  477. YGNodeStyleSetHeight(_yogaNode, size.height);
  478. }
  479. // IntrinsicContentSize
  480. static inline YGSize
  481. RCTShadowViewMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode)
  482. {
  483. RCTShadowView *shadowView = (__bridge RCTShadowView *)YGNodeGetContext(node);
  484. CGSize intrinsicContentSize = shadowView->_intrinsicContentSize;
  485. // Replace `UIViewNoIntrinsicMetric` (which equals `-1`) with zero.
  486. intrinsicContentSize.width = MAX(0, intrinsicContentSize.width);
  487. intrinsicContentSize.height = MAX(0, intrinsicContentSize.height);
  488. YGSize result;
  489. switch (widthMode) {
  490. case YGMeasureModeUndefined:
  491. result.width = intrinsicContentSize.width;
  492. break;
  493. case YGMeasureModeExactly:
  494. result.width = width;
  495. break;
  496. case YGMeasureModeAtMost:
  497. result.width = MIN(width, intrinsicContentSize.width);
  498. break;
  499. }
  500. switch (heightMode) {
  501. case YGMeasureModeUndefined:
  502. result.height = intrinsicContentSize.height;
  503. break;
  504. case YGMeasureModeExactly:
  505. result.height = height;
  506. break;
  507. case YGMeasureModeAtMost:
  508. result.height = MIN(height, intrinsicContentSize.height);
  509. break;
  510. }
  511. return result;
  512. }
  513. - (void)setIntrinsicContentSize:(CGSize)intrinsicContentSize
  514. {
  515. if (CGSizeEqualToSize(_intrinsicContentSize, intrinsicContentSize)) {
  516. return;
  517. }
  518. _intrinsicContentSize = intrinsicContentSize;
  519. if (CGSizeEqualToSize(_intrinsicContentSize, CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric))) {
  520. YGNodeSetMeasureFunc(_yogaNode, NULL);
  521. } else {
  522. YGNodeSetMeasureFunc(_yogaNode, RCTShadowViewMeasure);
  523. }
  524. YGNodeMarkDirty(_yogaNode);
  525. }
  526. // Local Data
  527. - (void)setLocalData:(__unused NSObject *)localData
  528. {
  529. // Do nothing by default.
  530. }
  531. // Flex
  532. - (void)setFlexBasis:(YGValue)value
  533. {
  534. RCT_SET_YGVALUE_AUTO(value, YGNodeStyleSetFlexBasis, _yogaNode);
  535. }
  536. - (YGValue)flexBasis
  537. {
  538. return YGNodeStyleGetFlexBasis(_yogaNode);
  539. }
  540. #define RCT_STYLE_PROPERTY(setProp, getProp, cssProp, type) \
  541. -(void)set##setProp : (type)value \
  542. { \
  543. YGNodeStyleSet##cssProp(_yogaNode, value); \
  544. } \
  545. -(type)getProp \
  546. { \
  547. return YGNodeStyleGet##cssProp(_yogaNode); \
  548. }
  549. RCT_STYLE_PROPERTY(Flex, flex, Flex, float)
  550. RCT_STYLE_PROPERTY(FlexGrow, flexGrow, FlexGrow, float)
  551. RCT_STYLE_PROPERTY(FlexShrink, flexShrink, FlexShrink, float)
  552. RCT_STYLE_PROPERTY(FlexDirection, flexDirection, FlexDirection, YGFlexDirection)
  553. RCT_STYLE_PROPERTY(JustifyContent, justifyContent, JustifyContent, YGJustify)
  554. RCT_STYLE_PROPERTY(AlignSelf, alignSelf, AlignSelf, YGAlign)
  555. RCT_STYLE_PROPERTY(AlignItems, alignItems, AlignItems, YGAlign)
  556. RCT_STYLE_PROPERTY(AlignContent, alignContent, AlignContent, YGAlign)
  557. RCT_STYLE_PROPERTY(Position, position, PositionType, YGPositionType)
  558. RCT_STYLE_PROPERTY(FlexWrap, flexWrap, FlexWrap, YGWrap)
  559. RCT_STYLE_PROPERTY(Overflow, overflow, Overflow, YGOverflow)
  560. RCT_STYLE_PROPERTY(Display, display, Display, YGDisplay)
  561. RCT_STYLE_PROPERTY(Direction, direction, Direction, YGDirection)
  562. RCT_STYLE_PROPERTY(AspectRatio, aspectRatio, AspectRatio, float)
  563. - (void)didUpdateReactSubviews
  564. {
  565. // Does nothing by default
  566. }
  567. - (void)didSetProps:(__unused NSArray<NSString *> *)changedProps
  568. {
  569. if (_recomputePadding) {
  570. RCTProcessMetaPropsPadding(_paddingMetaProps, _yogaNode);
  571. }
  572. if (_recomputeMargin) {
  573. RCTProcessMetaPropsMargin(_marginMetaProps, _yogaNode);
  574. }
  575. if (_recomputeBorder) {
  576. RCTProcessMetaPropsBorder(_borderMetaProps, _yogaNode);
  577. }
  578. _recomputeMargin = NO;
  579. _recomputePadding = NO;
  580. _recomputeBorder = NO;
  581. }
  582. @end