视图掩码和自动布局

8

我有一个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}]];
}

它能准确地给我想要的内容,但不会屏蔽信息:

views without masking

如果我再添加一行:

[self.viewToMask setMaskView:self.theMask];

两个视图都消失了 --- 小视图 (self.theMask) 遮盖了整个更大的视图 (self.viewToMask) ,即使它只有一半大小。有人理解这里发生了什么吗?您不能在自动布局中使用 UIView.maskView 吗?


1
我知道当你使用iOS 8之前的版本(-[CALayer maskLayer])时,你必须定位被遮罩层的坐标空间,并且遮罩层不存在于正常的视图层次结构中。我想知道这里是否有类似的情况? - Zev Eisenberg
这就是正在发生的事情。非常感谢。 - jefflovejapan
那么它的效果如何?您能在maskView中使用自动布局吗? - Zev Eisenberg
3个回答

6

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

proper masking


很酷。虽然看起来并不像你说的那样是中心的孔? - Zev Eisenberg
是的,遮罩是我之前想象的相反(清除像素会使被遮罩视图中的子视图显示出来)。我使用了这个解决方案来实现打孔效果:https://dev59.com/yGox5IYBdhLWcg3w9o-i - jefflovejapan

4

根据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中编写)


这实际上是一个非常聪明的技巧!至于代码中的注释 - 当视图不在层次结构中时,您无法设置约束。 - Andrzej Michnia

0
你可以通过将 maskView 设为普通子视图(例如在具有相关约束的 storyboard 中)并仅在 viewWillLayoutSubviews 中将其设置为 maskView,使自动布局与您的 maskView 协同工作。即:

-(void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];

    self.viewToBeMasked.maskView = self.maskViewWithLayoutConstraints;
}

这对我来说不起作用,除非嵌套遮罩视图。这有点奇怪。 :/ 我会将其发布为替代答案。 - DevAndArtist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接