Skip to content

Commit 26e373c

Browse files
majakFacebook Github Bot
authored and
Facebook Github Bot
committed
fix view clipping to operate on ui hierachy
Summary: There was a bug in the view clipping logic. Clipping works on uiview hierarchy, but I've been using `reactSuperview` to get clipping rect for my parent. This is incorrect in a case where these two hierarchies don't match and there are some views between a view and its `reactSuperview`. So we should really use normal `superview`. A minor complication is that `superview` is `nil` if we are clipped. We could remember what our last `superview` was, but that's extra data we have to manage. Instead I use one clever trick to avoid doing so. (Let me know if it makes sense based on my inline documentation.) Reviewed By: mmmulani Differential Revision: D4182647 fbshipit-source-id: 779cbcec0bd08eb270c3727c9c5cb9c080c4a2a4
1 parent b123cc2 commit 26e373c

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

Examples/UIExplorer/UIExplorerUnitTests/RCTSubviewClippingTests.m

+35
Original file line numberDiff line numberDiff line change
@@ -369,4 +369,39 @@ - (void)testScrollViewClipsDuringScrolling
369369
XCTAssert([[NSSet setWithArray:contentView.subviews] isEqualToSet:[NSSet setWithArray:(@[rowView2, rowView3])]]);
370370
}
371371

372+
373+
/**
374+
In this test case the react view hiearchy is
375+
clippingView -> directReactChildView -> deeperChildView
376+
while the uiview hierarchy is
377+
clippingView -> nonReactChildView -> directReactChildView -> deeperChildView
378+
*/
379+
- (void)testClippingWhenReactHierarchyDoesntMatchUIHierarchy
380+
{
381+
RCTView *clippingView = [RCTView new];
382+
[clippingView reactSetFrame:CGRectMake(0, 0, 50, 50)];
383+
384+
RCTView *directReactChildView = [RCTView new];
385+
[directReactChildView reactSetFrame:CGRectMake(-50, 0, 100, 50)];
386+
[clippingView insertReactSubview:directReactChildView atIndex:0];
387+
[clippingView didUpdateReactSubviews];
388+
389+
RCTView *deeperChildView = [RCTView new];
390+
[deeperChildView reactSetFrame:CGRectMake(0, 0, 50, 50)];
391+
[directReactChildView insertReactSubview:deeperChildView atIndex:0];
392+
[directReactChildView didUpdateReactSubviews];
393+
394+
UIView *nonReactChildView = [UIView new];
395+
[nonReactChildView setFrame:CGRectMake(50, 0, 50, 50)];
396+
[clippingView addSubview:nonReactChildView];
397+
[nonReactChildView addSubview:directReactChildView];
398+
399+
[clippingView rct_setRemovesClippedSubviews:YES];
400+
[directReactChildView reactSetFrame:CGRectMake(-50, 0, 99, 50)];
401+
402+
XCTAssertEqual(clippingView.subviews.count, 1u);
403+
XCTAssertEqual(nonReactChildView.subviews.count, 1u);
404+
XCTAssertEqual(directReactChildView.subviews.count, 1u);
405+
}
406+
372407
@end

React/Views/UIView+React.m

+6-2
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,12 @@ - (void)rct_reclip
287287
if (!self.rct_nextClippingView && !self.rct_removesClippedSubviews) {
288288
return;
289289
}
290-
// If we are currently clipped our active clipping rect would be null rect. That's why we ask for out superview's.
291-
CGRect clippingRectForSuperview = self.reactSuperview ? [self.reactSuperview rct_activeClippingRect] : CGRectInfinite;
290+
// If we are currently clipped our active clipping rect would be null rect. That's why we ask for our superview's.
291+
// Actually it's not that simple. Clipping logic operates on uiview hierarchy. If the current view is clipped we cannot use its superview, since its nil.
292+
// Fortunately we can use `reactSuperview`. UI and React view hierachies doesn't have to match, but when they don't match we don't clip.
293+
// Therefore because this view is clipped it means its reactSuperview is the same as its (clipped) UI superview.
294+
UIView *clippingRectSource = self.superview ? self.superview : self.reactSuperview;
295+
CGRect clippingRectForSuperview = clippingRectSource ? [clippingRectSource rct_activeClippingRect] : CGRectInfinite;
292296
if (CGRectIsNull(clippingRectForSuperview)) {
293297
return;
294298
}

0 commit comments

Comments
 (0)