Swift 如何遮盖形状图层以模糊图层

Swift how to mask shape layer to blur layer

我做的是一个进度圈,希望它的轨道路径有模糊效果,有什么办法可以实现吗?

原来的轨道是这样的(轨道路径是透明的,我要模糊)

这是我的尝试

let outPutViewFrame = CGRect(x: 0, y: 0, width: 500, height: 500)
let circleRadius: CGFloat = 60
let circleViewCenter = CGPoint(x: outPutViewFrame.width / 2 , y: outPutViewFrame.height / 2)
let circleView = UIView()
let progressWidth: CGFloat = 8

circleView.frame.size = CGSize(width: (circleRadius + progressWidth) * 2, height: (circleRadius + progressWidth) * 2)
circleView.center = circleViewCenter


let circleTrackPath = UIBezierPath(arcCenter: CGPoint(x: circleView.frame.width / 2, y: circleView.frame.height / 2), radius: circleRadius, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)
let blur = UIBlurEffect(style: .light)
let blurEffect = UIVisualEffectView(effect: blur)
blurEffect.frame = circleView.bounds
blurEffect.mask(withPath: circleTrackPath, inverse: false)

extension UIView {

    func mask(withPath path: UIBezierPath, inverse: Bool = false) {
    
        let maskLayer = CAShapeLayer()

        if inverse {
            path.append(UIBezierPath(rect: self.bounds))
            maskLayer.fillRule = CAShapeLayerFillRule.evenOdd
        }
        
        maskLayer.path = path.cgPath
        maskLayer.lineWidth = 5
        maskLayer.lineCap = CAShapeLayerLineCap.round
       

        self.layer.mask = maskLayer
    }
}
  • maskLayer.fillRule 设置为 evenOdd,即使不是 inversed

      if inverse {
          path.append(UIBezierPath(rect: self.bounds))
      }
      maskLayer.fillRule = CAShapeLayerFillRule.evenOdd
    
  • 使用大圆和小圆创建circleTrackPath

      let circleCenter = CGPoint(x: circleView.frame.width / 2, y: circleView.frame.height / 2)
      let circleTrackPath = UIBezierPath(ovalIn: 
          CGRect(origin: circleCenter, size: .zero)
              .insetBy(dx: circleRadius, dy: circleRadius))
      // smaller circle
      circleTrackPath.append(CGRect(origin: circleCenter, size: .zero)
              .insetBy(dx: circleRadius * 0.8, dy: circleRadius * 0.8))
    
  • circleTrackPath.usesEvenOddFillRule设为真:

      circleTrackPath.usesEvenOddFillRule = true
    

现在你有一个模糊的完整圆圈。非模糊弧部分可以作为另一个子层实现。

这是您可以粘贴到 playground 中的 MCVE:

let container = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))

// change this to a view of your choice
let image = UIImageView(image: UIImage(named: "my_image"))
let blur = UIVisualEffectView(effect: UIBlurEffect(style: .light))
container.addSubview(image)
blur.frame = image.frame
container.addSubview(blur)
let outer = image.bounds.insetBy(dx: 30, dy: 30)
let path = UIBezierPath(ovalIn: outer)
path.usesEvenOddFillRule = true
path.append(UIBezierPath(ovalIn: outer.insetBy(dx: 10, dy: 10)))

let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
maskLayer.fillRule = .evenOdd
blur.layer.mask = maskLayer
container // <--- playground quick look this

使用我的个人资料图片作为背景,这会产生: