如何在图层蒙版内绘制?

3

enter image description here

我正在使用以下代码生成此内容(在drawRect内部):
let path = CGMutablePath()
path.addArc(center: self.circleCenter, radius: radius, startAngle: 0.0, endAngle: 2 * 3.14, clockwise: false)

let whitePath = UIBezierPath(cgPath: path)
UIColor.white.setStroke()
whitePath.lineWidth = 3
whitePath.stroke()


path.addRect(CGRect(x: 0, y: 0, width: frame.width, height: frame.height))

let maskLayer = CAShapeLayer()
maskLayer.backgroundColor = UIColor.black.cgColor
maskLayer.path = path
maskLayer.fillRule = kCAFillRuleEvenOdd

layer.mask = maskLayer

然而,我想将圆形的顶部涂白,使整个圆形内部都是白色的,但我不确定该如何做到这一点,因为我已经将我的layer.mask设置为CAShape Layer,所以我在这个圆形内部所做的任何绘画都不会显示出来。
遮罩必须是一个圆形,因为实际上对于我的大多数用例,对于这个自定义UIView,它不会剪切另一个视图的顶部,所以使用圆形效果很好。如何覆盖圆形的顶部区域?
编辑:我希望这部分(我在红圈处)被填充成白色:

enter image description here

我希望最终的图像看起来像这样(抱歉质量不佳,这是我在iPad上手动画的):

enter image description here


一般来说,在drawRect中操作图层是不可取的,因为它发生在渲染周期的太晚阶段。如果您想添加蒙版,请在layoutSubviews中进行操作。 - Rob
1
完全没有关系,我建议使用.pi而不是键入3.14。此外,我不确定为什么要创建CGMutablePath而不是直接创建UIBezierPath - Rob
抱歉,也许我的措辞有些令人困惑。我已经回过头来添加了额外的照片,以便清楚地展示我想要的东西。而且我正在使用CGPath,因为layer.mask需要一个CGPath,而不是UIBezierPath。 - jjjjjjjj
是的,"Messaging" 是从下面的一个视图中来的。暗影视图是在顶部的一个 UIView,我在暗影视图中有一个遮罩,所以我可以透过它看到下面的内容。据我所知,如果你想要在一个 UIView 中“切一个洞”,就像我正在做的那样,你需要使用一个遮罩(除非还有其他我不知道的方法)。 - jjjjjjjj
2个回答

3

您说:

... "Messaging" 是从下面的视图中获取的。深色阴影视图是在顶部的一个 UIView,我在深色阴影视图中有一个遮罩,所以我可以看到它下面的内容。

这里有两种方法:

  1. If you really want to use masks, you need a complicated view hierarchy that has four main views: The root view (white), the chrome view (the view with all the chrome that will be masked when you add your circle mask; e.g. that top part of your circle that you need masked out), the UI element view(s) that will not be masked when you add your masks to the chrome and the dimming view), and the dimming view (which will also get masked). These latter three need to be subviews of the main view (don't put the messages button on the chrome view, but make it its own view, so when you mask the chrome out, these UI elements won't get masked out).

    You end up with something like the following (this is showing after the masks have been added):

    enter image description here

    You can then make dimming view visible and mask it and the background view:

    @IBAction func didTapButton(_ sender: Any) {
        dimmingView.alpha = 0.5
        let center = messagingView.center
        let radius = messagingView.frame.width * 0.7
    
        mask(center: center, radius: radius, in: messagingView.superview!, on: dimmingView)
        mask(center: center, radius: radius, in: messagingView.superview!, on: backgroundView)
    }
    
    private func mask(center: CGPoint, radius: CGFloat, in view: UIView, on viewToMask: UIView) {
        let point = view.convert(center, to: viewToMask)
        let path = UIBezierPath(rect: viewToMask.bounds)
        path.addArc(withCenter: point, radius: radius, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
        let mask = CAShapeLayer()
        mask.fillColor = UIColor.white.cgColor
        mask.path = path.cgPath
        mask.fillRule = kCAFillRuleEvenOdd
        viewToMask.layer.mask = mask
    }
    

    Thus with the dimming view not visible and no masks in place, you have the before view:

    enter image description here

    And then after the dimming view is made visible and both it and the "chrome" view are masked:

    enter image description here

  2. Easier, IMHO, would be to:

    • take snapshot of messages view;
    • add dimming view (obscuring the messages view);
    • add circle view (opaque and white) on top of the dimming view; and
    • add snapshot (or another rendition) of messages view on top of the circle.

    This will yield an effect of feeling like you're "revealing" the messages button, but what you're really doing is adding your dimming view, a circle, and another rendition of the messages button. This avoids all of the clumsiness of adding of masks to various views.


1
一个遮罩不会绘制,它只能进行遮罩操作。如果你想强制圆形的一部分变为白色,你需要用白色进行绘制。如果你正在覆盖drawRect方法,那么在绘制图像后,只需绘制你想要变为白色的区域即可。
如果你想创建一个视图,而不是覆盖drawRect方法,这通常是更好的方法,你可以在视图的层上设置一个遮罩层,并在图像视图顶部添加另一个形状层,其中包含你的白色形状。

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