如何绘制内层的蒙版?

How to draw inside layer's mask?

我正在使用以下代码生成此代码(在 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 层,所以我在这个圆圈内所做的任何绘图都不会显示出来。

掩码需要是一个圆圈,因为实际上对于我的大多数用例,对于这个自定义 UIView,它不会剪切另一个视图的顶部,所以使用圆圈效果很好。如何绘制圆的顶部区域?

编辑:我希望这部分(我用红色圈出的地方)填充为白色:

所以我希望最终图像看起来像(抱歉质量不好,在我的 iPad 上手动绘制):

面具不是画的,它是面具。如果你想强制你的圆圈的一部分变成白色,你需要画成白色。如果您要覆盖 drawRect,只需在绘制图像后绘制您想要的白色区域。

如果您想创建一个视图来执行您想要的操作而不覆盖 drawRect,这通常是更好的方法,您可以在视图层上设置一个遮罩层,并在顶部添加另一个形状层包含白色形状的图像视图。

你说:

... the "Messaging" is from a view underneath. The dark shadow view is a UIView on top, and I have a mask in the dark shadow view so I can see through underneath it.

这里有两种方法:

  1. 如果你真的想使用掩码,你需要一个复杂的视图层次结构,它有四个主要视图:根视图(白色),chrome视图(包含所有视图的视图) chrome 添加圆形遮罩时将被遮罩;例如,您需要遮罩的圆的顶部),添加您的 UI 元素视图时不会被遮罩chrome 和调光视图的遮罩)和调光视图(也将被遮罩)。后三个需要是主视图的子视图(不要将消息按钮放在 chrome 视图上,而是使其成为自己的视图,所以当你屏蔽 chrome 时,这些 UI 元素不会被屏蔽掉)。

    你最终会得到类似下面的结果(这是在添加蒙版后显示的):

    然后您可以使调光视图可见并屏蔽它和背景视图:

    @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
    }
    

    因此,在调光视图不可见且没有遮罩的情况下,您可以看到之前的视图:

    然后在调暗视图可见并且它和 "chrome" 视图都被屏蔽后:

  2. 恕我直言,更简单的方法是:

    • 截取消息视图快照;
    • 添加调光视图(模糊消息视图);
    • 在调光视图的顶部添加圆形视图(不透明和白色);和
    • 在圆圈顶部添加消息视图的快照(或其他再现)。

    这会产生一种感觉,就像您是 "revealing" 消息按钮一样,但您真正在做的是添加变暗视图、一个圆圈和消息按钮的另一种形式。这避免了向各种视图添加蒙版的所有笨拙。