【问题标题】:How to draw inside layer's mask?如何在图层的蒙版内绘制?
【发布时间】:2017-11-10 14:51:40
【问题描述】:

我正在使用以下代码来生成这个(在 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 中操作图层是不可取的,因为它在渲染周期中发生得太晚了。如果要添加蒙版,请在 layoutSubviews 中进行。
  • 完全不相关,而不是输入3.14,我建议使用.pi。另外,我不确定您为什么要创建 CGMutablePath 而不是直接创建 UIBezierPath
  • 对不起,我的措辞可能令人困惑。我已经返回并添加了其他照片以准确显示我想要的内容。我正在使用 CGPath,因为 layer.mask 采用 CGPath,而不是 UIBezierPath。
  • 是的,“消息”来自下方的视图。暗影视图是顶部的 UIView,我在暗影视图中有一个蒙版,所以我可以看到它下面。据我所知,如果你想在 UIView 中“切一个洞”,就像我正在做的那样,你需要使用遮罩(除非有另一种我不知道的方法)

标签: ios core-graphics


【解决方案1】:

你说:

...“消息”来自下面的视图。暗影视图是顶部的 UIView,我在暗影视图中有一个蒙版,所以我可以看到它下面。

这里有两种方法:

  1. 如果你真的想使用蒙版,你需要一个复杂的视图层次结构,它有四个主要视图:根视图(白色)、镶边视图(当你添加圆形蒙版时,所有镶边的视图都将被蒙版) ; 例如,您需要屏蔽的圆圈的顶部),当您将蒙版添加到 chrome 和调光视图时不会被屏蔽的 UI 元素视图)和调光视图(也将获得蒙面)。后三个需要是主视图的子视图(不要将消息按钮放在 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. 恕我直言,更容易的是:

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

    这会产生一种感觉,就像您正在“显示”消息按钮一样,但您真正要做的是添加调暗视图、圆圈和消息按钮的另一个再现。这避免了为各种视图添加蒙版的所有笨拙。

【讨论】:

    【解决方案2】:

    蒙版不会绘制,它会蒙版。如果你想强制你的圈子变成白色,你需要画成白色。如果您要覆盖drawRect,只需在绘制图像后绘制您想要为白色的区域。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-11
      • 2019-11-25
      • 2014-09-13
      • 1970-01-01
      相关资源
      最近更新 更多