How Does Clipstobounds Work

How does clipsToBounds work?

If my superview is a box measuring 10 units on each side, and my subview is 20 units wide, with clipsToBounds set to YES, I'll only see the part of the subview that fits within the bounds of the superview. Otherwise, if clipsToBounds is set to NO, I'll see the entire subview, even the parts outside the superview (assuming we're still on the screen).

As a visual example, consider the following views set up on the storyboard:

Sample Image

This is a white UIView, a label in the top left corner with either a simple "1" or "2" so that I can discuss these as view1 or view2. Additionally, the black view is the same size as the white view, but it's origin is at the white view's center.

In the view controller's viewDidLoad method, we have the following code:

Objective-C:

- (void)viewDidLoad {
[super viewDidLoad];
self.view1.clipsToBounds = YES;
self.view2.clipsToBounds = NO;
}

Swift:

override func viewDidLoad() {
super.viewDidLoad()
self.view1.clipsToBounds = true
self.view2.clipsToBounds = false
}

When we run the code and look at in the simulator or on the device, we get the following results:

Sample Image

So, despite these views being set up identically (except clipsToBounds), they look different. This is what clipsToBounds does. Setting it to YES will provide the top result, while setting it to NO provides the bottom result.

If we debug the view hierarchy, we can see more clearly that the black boxes both do actually extend past the boarders of the white view, but only view 2 shows this when the app is actually running:

Sample Image

masksToBounds vs. clipsToBounds

masksToBounds

Any sublayers of the layer that extend outside its boundaries will be clipped to those boundaries. Think of the layer, in that case, as a window onto its sublayers; anything outside the edges of the window will not be visible. When masksToBounds is NO, no clipping occurs.

When the value of this property is true, Core Animation creates an implicit clipping mask that matches the bounds of the layer and includes any corner radius effects. If a value for the mask property is also specified, the two masks are multiplied to get the final mask value.

you can get the more information in API Reference.

clipToBounds

The use case for clipsToBounds is more for subviews which are partially outside the main view. For example, I have a (circular) subview on the edge of its parent (rectangular) UIView. If you set clipsToBounds to YES, only half the circle/subview will be shown. If set to NO, the whole circle will show up. Just encountered this so wanted to share

for more information sample link

Why does clipsToBounds prevent the subviews to be touched?

My understanding is that the hit test starts from the subview and work its way up to the superview.

Then your understanding is completely wrong. Let’s fix that. First, let's clear up some other misunderstandings:

  • The reversed is a total red herring; it has nothing to do with it. The subviews are always tested in reverse order, because a subview in front needs to take precedence over a subview behind.

  • The clipsToBounds is a total red herring too. All it does is change whether you can see a subview outside its superview; it does not have any effect on whether you can touch a subview outside its superview.

Okay, so how does this work? Let's take view V which contains a subview A. Let's suppose that A is outside V. Assume you can see A, and you tap A.

Now hit-testing begins. But here's the thing: it starts at the level of the window, and works its way down the view hierarchy. So the window starts by interrogating its subviews; there is just one, the main view of the view controller.

So now we recurse, and the main view of the view controller interrogates its subviews. One of those is V. "Hey, V, was the tap inside you?" "No!" (You have to agree that that is the correct answer, because we already said that A is outside V.)

So the main view of the view controller gives up on V, and never finds out that the tap was on A, because we never recursed down that far. So it reports back up the chain: "The tap was not on any of my subviews, so I have to report that the tap was on me." The tap has fallen through to the view controller's main view.

But you can change that behaviour by overriding the implementation of hitTest:

override func hitTest(_ point: CGPoint, with e: UIEvent?) -> UIView? {
if let result = super.hitTest(point, with:e) {
return result
}
for sub in self.subviews.reversed() {
let pt = self.convert(point, to:sub)
if let result = sub.hitTest(pt, with:e) {
return result
}
}
return nil
}

UIView clipsToBounds doesn't work

I found a solution, I move the clipsToBound in the viewDidLayoutSubviews instead viewDidLoad and now works

override func viewDidLoad() {
super.viewDidLoad()

contentView.layer.cornerRadius = Dimensions.CornerRaius
contentView.dropShadow()
}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()

contentView.clipsToBounds = true
}

ClipsToBounds is not working in cells

You should set the clipsToBounds property of the higher level container view (like the contentView of your cell.)

Why does UITextView set clipsToBounds to true by default?

For a UIScrollView, clipsToBounds is set to true by default. I think this so that its subviews disappear as they get scrolled beyond its bounds. I guess UITextView just inherits this setting.

I think that's OK, but I'd suggest adding the subview to the superview of your UITextView instead.

clipsToBounds causes UIImage to not display in iOS10 & XCode 8

I had the same problem and calling layoutIfNeeded before all the rounded corner / clipsToBounds stuff fixed the issue. iOS 10 GM with xcode 8 GM causes views to disappear due to roundedCorners & clipsToBounds



Related Topics



Leave a reply



Submit