屏蔽 UIView 和自动布局

Masking a UIView and Auto Layout

我有一个 UIView,我想用另一个 UIView 遮盖,在它的中心打一个洞。这是我的 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}]];
}

它给了我想要的东西,减去掩蔽:

如果我再添加一行:

[self.viewToMask setMaskView:self.theMask];

两个视图都消失了 --- 小视图 (self.theMask) 掩盖了整个大视图 (self.viewToMask),即使它只有一半大小。有谁知道这里发生了什么?可以不使用 UIView.maskView 和自动布局吗?

正如 Zev 所解释的,遮罩视图存在于普通视图层次结构之外,因此不能与自动布局一起使用。我通过将它手动放置在我的视图控制器的 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];
}

您可以通过将 maskView 设为普通子视图(例如,在具有相关约束的故事板中)然后仅在 viewWillLayoutSubviews 中将其设置为 maskView 来使自动布局与您的 maskView 一起工作。即:

-(void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];

    self.viewToBeMasked.maskView = self.maskViewWithLayoutConstraints;
}

根据 Russ' 的回答,我进行了自己的研究并找到了替代解决方法。

下面的代码示例将用 10pt 遮盖主视图的左侧和右侧。重要

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? */
    }
}

此代码使用 iOS 9.0 和 Swift 2.0 中可用的 AutoLayout 语法。 (写于Xcode 7 beta 4)