I have a UIView that I want to mask with another UIView, punching a hole out of its center. Here's my viewDidLoad
:
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.viewToMask];
[self.view addSubview:self.theMask];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.viewToMask attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.viewToMask attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"[cyan(200)]" options:0 metrics:nil views:@{@"cyan": self.viewToMask}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[cyan(200)]" options:0 metrics:nil views:@{@"cyan": self.viewToMask}]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.theMask attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.viewToMask attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.theMask attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.viewToMask attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"[mask(100)]" options:0 metrics:nil views:@{@"mask": self.theMask}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[mask(100)]" options:0 metrics:nil views:@{@"mask": self.theMask}]];
}
It gives me exactly what I'm looking for, minus the masking:
If I add one more line:
[self.viewToMask setMaskView:self.theMask];
both views disappear --- the small view (self.theMask
) masks out the whole larger view (self.viewToMask
) even though it's only half the size. Does anyone understand what's going on here? Can you not use UIView.maskView
with Auto Layout?
As Zev explained, the mask view lives outside of the ordinary view hierarchy and so can't be used together with Auto Layout. I got around this by placing it manually in my view controller's viewDidLayoutSubviews
:
-(void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
CGRect viewToMaskRect = self.viewToMask.bounds;
CGRect maskRect = CGRectMake(viewToMaskRect.origin.x + 50.0, viewToMaskRect.origin.y + 50.0, 100.0, 100.0);
[self.theMask setFrame:maskRect];
[self.viewToMask setMaskView:self.theMask];
}
Based on Russ'
answer I did my own research and got an alternative workaround.
The code sample below will mask the left and right side of the main view with 10pt. Important
class SomeViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.whiteColor()
self.setupMaskView()
}
private func setupMaskView() {
let maskView = UIView()
maskView.translatesAutoresizingMaskIntoConstraints = false
maskView.backgroundColor = UIColor(white: 0.0, alpha: 1.0)
let maskContainerView = UIView()
maskContainerView.addSubview(maskView)
self.view.addSubview(maskContainerView)
maskView.leftAnchor.constraintEqualToAnchor(self.view.leftAnchor, constant: 10).active = true
maskView.widthAnchor.constraintEqualToAnchor(self.view.widthAnchor, constant: -20).active = true
maskView.heightAnchor.constraintEqualToAnchor(self.view.heightAnchor).active = true
self.view.maskView = maskContainerView // this will not work it we place this line above the constraint code !!!
/* I have no idea why this does not work and why nesting is required, maybe some sort of bug? */
}
}
This code is using AutoLayout syntax available from iOS 9.0 and Swift 2.0. (Written in Xcode 7 beta 4)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With