From 409de4c0fe82def7e79cb2278239573f31adfd42 Mon Sep 17 00:00:00 2001 From: Nick Lefever Date: Thu, 21 Mar 2024 21:14:37 +0100 Subject: [PATCH] [fabric] Fix View content clipping to bounds toggling randomly on mount Summary: React View components take the assumption that content clipping to the view's bounds is disabled by default. This diff fixes the propagation of the clipping setting to the `RCTUIView` instance and the backing core animation layer, by keeping both settings in sync with the component props. Core Animation on macOS also enabled clipping when a corner radius (border radius) is set on the layer. This would result in the random toggling of the clipping (overflow style) on the native view and make it out of sync with the component properties. This is being fixed by restoring the current `clipsToBounds` setting after setting the layer's corner radius property. Test Plan: - Run Cosmo Studio - Open the UI Reference (Developer > Show UI Reference) - Open the 'Inputs' example - Switch between other examples and back to 'Inputs' to verify that the clipping stays unchanged. | Before | After | |--| | https://pxl.cl/4xDWc | https://pxl.cl/4xDWt | Reviewers: shawndempsey, bedeoverend, #rn-desktop, #cosmo Reviewed By: bedeoverend Subscribers: generatedunixname499725568 Differential Revision: https://phabricator.intern.facebook.com/D55213691 Tasks: T182033885 Tags: uikit-diff # Conflicts: # packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm --- .../View/RCTViewComponentView.mm | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index 8d18b7ee2822e8..070cd32d3212a0 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -61,7 +61,10 @@ - (instancetype)initWithFrame:(CGRect)frame _reactSubviews = [NSMutableArray new]; #if !TARGET_OS_OSX // [macOS] self.multipleTouchEnabled = YES; -#endif // [macOS] +#else // [macOS + // React views have their bounds clipping disabled by default + self.clipsToBounds = NO; +#endif // macOS] } return self; } @@ -762,6 +765,17 @@ static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle) } #endif // macOS] +#if TARGET_OS_OSX // [macOS +- (void)setClipsToBounds:(BOOL)clipsToBounds +{ + // Set the property managed by RCTUIView + super.clipsToBounds = clipsToBounds; + + // Bounds clipping must also be configured on the view's layer + self.layer.masksToBounds = clipsToBounds; +} +#endif // macOS] + - (void)invalidateLayer { CALayer *layer = self.layer; @@ -845,8 +859,17 @@ - (void)invalidateLayer CGColorRef borderColor = RCTCreateCGColorRefFromSharedColor(borderMetrics.borderColors.left); layer.borderColor = borderColor; CGColorRelease(borderColor); +#if TARGET_OS_OSX // [macOS] layer.cornerRadius = (CGFloat)borderMetrics.borderRadii.topLeft; +#else // [macOS + // Setting the corner radius on view's layer enables back clipping to bounds. To + // avoid getting the native view out of sync with the component's props, we make + // sure that clipsToBounds stays unchanged after setting the corner radius. + BOOL clipsToBounds = self.clipsToBounds; + layer.cornerRadius = (CGFloat)borderMetrics.borderRadii.topLeft; + self.clipsToBounds = clipsToBounds; +#endif // macOS] layer.cornerCurve = CornerCurveFromBorderCurve(borderMetrics.borderCurves.topLeft); layer.backgroundColor = _backgroundColor.CGColor;