Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Masking a UIView and Auto Layout

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:

views without 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?

like image 888
jefflovejapan Avatar asked Jan 28 '15 02:01

jefflovejapan


2 Answers

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];
}

proper masking

like image 133
jefflovejapan Avatar answered Sep 18 '22 16:09

jefflovejapan


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)

like image 30
DevAndArtist Avatar answered Sep 19 '22 16:09

DevAndArtist