diff --git a/packages/react-native/React/Views/RCTView.h b/packages/react-native/React/Views/RCTView.h index ddfcdd9be6bea0..f6942b2a653ecf 100644 --- a/packages/react-native/React/Views/RCTView.h +++ b/packages/react-native/React/Views/RCTView.h @@ -105,7 +105,8 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; @property (nonatomic, assign) CGFloat borderBlockEndWidth; @property (nonatomic, assign) CGFloat borderBlockStartWidth; -@property (nonatomic, strong) NSString* transformOrigin; +@property (nonatomic, strong) NSString* transformOriginProp; +@property (assign) CATransform3D transformProp; /** * Border curve. */ diff --git a/packages/react-native/React/Views/RCTView.m b/packages/react-native/React/Views/RCTView.m index 277a78f6435091..14c894f0594147 100644 --- a/packages/react-native/React/Views/RCTView.m +++ b/packages/react-native/React/Views/RCTView.m @@ -137,7 +137,8 @@ - (instancetype)initWithFrame:(CGRect)frame _hitTestEdgeInsets = UIEdgeInsetsZero; _backgroundColor = super.backgroundColor; - _transformOrigin = nil; + _transformOriginProp = nil; + _transformProp = CATransform3DIdentity; } return self; @@ -595,10 +596,6 @@ - (void)layoutSubviews if (_removeClippedSubviews) { [self updateClippedSubviews]; } - - if (_transformOrigin != nil) { - RCTApplyTransformWithTransformOrigin(self, _transformOrigin, self.layer.transform); - } } - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection @@ -782,9 +779,31 @@ - (void)reactSetFrame:(CGRect)frame [super reactSetFrame:frame]; if (!CGSizeEqualToSize(self.bounds.size, oldSize)) { [self.layer setNeedsDisplay]; + + // Only transform if we have a transformOrigin prop + if (self.transformOriginProp != nil) { + RCTApplyTransformWithTransformOrigin(self, self.transformOriginProp, self.transformProp); + } } } +- (void)didSetProps:(NSArray *)changedProps { + for (NSString *propName in changedProps) { + if ([propName isEqualToString:@"transform"] || [propName isEqualToString:@"transformOrigin"]) { + if (self.transformOriginProp != nil && (self.bounds.size.width > 0 + || self.bounds.size.height > 0)) { + RCTApplyTransformWithTransformOrigin(self, self.transformOriginProp, self.transformProp); + } else { + self.layer.transform = self.transformProp; + } + + // Enable edge antialiasing in rotation, skew, or perspective transforms + self.layer.allowsEdgeAntialiasing = + self.layer.transform.m12 != 0.0f || self.layer.transform.m21 != 0.0f || self.layer.transform.m34 != 0.0f; + } + } +} + - (void)displayLayer:(CALayer *)layer { if (CGSizeEqualToSize(layer.bounds.size, CGSizeZero)) { diff --git a/packages/react-native/React/Views/RCTViewManager.m b/packages/react-native/React/Views/RCTViewManager.m index 32b983cd02cd41..e5c996d0bf7cfe 100644 --- a/packages/react-native/React/Views/RCTViewManager.m +++ b/packages/react-native/React/Views/RCTViewManager.m @@ -177,21 +177,12 @@ - (RCTShadowView *)shadowView RCT_CUSTOM_VIEW_PROPERTY(transform, CATransform3D, RCTView) { CATransform3D _transform = json ? [RCTConvert CATransform3D:json] : defaultView.layer.transform; - if (view.transformOrigin != nil) { - RCTApplyTransformWithTransformOrigin(view, view.transformOrigin, _transform); - } else { - view.layer.transform = _transform; - } - - // Enable edge antialiasing in rotation, skew, or perspective transforms - view.layer.allowsEdgeAntialiasing = - view.layer.transform.m12 != 0.0f || view.layer.transform.m21 != 0.0f || view.layer.transform.m34 != 0.0f; + view.transformProp = _transform; } RCT_CUSTOM_VIEW_PROPERTY(transformOrigin, NSString*, RCTView) { - view.transformOrigin = json; - RCTApplyTransformWithTransformOrigin(view, json, view.layer.transform); + view.transformOriginProp = json; } RCT_CUSTOM_VIEW_PROPERTY(accessibilityRole, UIAccessibilityTraits, RCTView)