UIVisualEffectView带蒙版层

17

我正在尝试在显示一个圆形蒙版的情况下模糊MKMapView的背景。为了更好地可视化我的意思,您可以在附加的图像中找到当前状态的图像:

Current State

这几乎展示了我想要的东西,但是背景(地图)应该是模糊的,而在这张图片中不是这样。我尝试使用UIVisualEffectView,但似乎我在那里做错了什么。以下是我尝试过的:

func createOverlay(at: CGPoint) {
    var blur: UIView!
    blur = UIVisualEffectView (effect: UIBlurEffect (style: UIBlurEffectStyle.dark))

    blur.frame = self.mapView.frame
    blur.isUserInteractionEnabled = false
    self.mapView.addSubview(blur)

    let circleSize: CGFloat = 200

    let path = UIBezierPath (
        roundedRect: blur.frame,
        cornerRadius: 0)

    let circle = UIBezierPath (
        roundedRect: CGRect (origin: CGPoint(x:at.x - circleSize/2, y: at.y-circleSize/2),
                             size: CGSize (width: circleSize, height: circleSize)), cornerRadius: circleSize/2)

    path.append(circle)
    path.usesEvenOddFillRule = true

    let maskLayer = CAShapeLayer()
    maskLayer.path = path.cgPath
    maskLayer.fillRule = kCAFillRuleEvenOdd

    let borderLayer = CAShapeLayer()
    borderLayer.path = circle.cgPath
    borderLayer.strokeColor = UIColor.white.cgColor
    borderLayer.lineWidth = 10
    blur.layer.addSublayer(borderLayer)

    blur.layer.mask = maskLayer
}
总结我的问题如下: 我需要如何更改我的代码,才能使地图视图模糊,并在其上方显示圆形蒙版?

编辑 刚刚发现,如果我删除添加圆形蒙版的代码,则地图视图的模糊效果可以实现...或许这对解决问题有帮助。


你尝试过将可视化效果视图添加到地图视图之上而不是作为子视图吗? - Nailer
不确定这是否有用,但这个人已经列出了他的游乐场代码来实现你想要的功能:http://stackoverflow.com/questions/38510476/blur-on-mkmapview - Jack Chorley
你的意思是用 self.view.insertSubview(blur, aboveSubview: self.mapView) 代替 self.mapView.addSubview(blur) 吗?我尝试了一下,但没有看到任何变化。 - dehlen
@JackC 这基本上是和我的代码一样的。我刚刚检查了一下:当我移除圆形遮罩时,地图视图上的模糊效果可以正常工作。但是如果我添加圆形遮罩代码,模糊效果就会消失... - dehlen
@dehlen,此时我也在寻找解决方案。)))) 是的,如果我删除layer.mask,模糊就可以正常工作,但视觉效果会在圆形内部添加模糊。 - dev.nikolaz
显示剩余2条评论
2个回答

20

我在挖掘一段时间后找到了一个解决方案。我假设你正在使用Xcode 8,因为layer.mask存在已知的bug,即您不能在同一层上同时具有模糊和蒙版。

通过玩具场所摆弄,我已经解决了这个问题,因此将尝试调整您的代码以匹配我的解决方案。如果您改用blurView的"mask"属性,则不应该有任何问题。据我所知,已经向苹果报告了有关layer.mask无法工作的bug。

这是您当前代码的结尾

let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
maskLayer.fillRule = kCAFillRuleEvenOdd

let borderLayer = CAShapeLayer()
borderLayer.path = circle.cgPath
borderLayer.strokeColor = UIColor.white.cgColor
borderLayer.lineWidth = 10
blur.layer.addSublayer(borderLayer)

blur.layer.mask = maskLayer

不要使用这个,尝试使用以下内容:

let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
maskLayer.fillRule = kCAFillRuleEvenOdd

let borderLayer = CAShapeLayer()
borderLayer.path = circle.cgPath
borderLayer.strokeColor = UIColor.white.cgColor
borderLayer.fillColor = UIColor.clear.cgColor //Remember this line, it caused me some issues
borderLayer.lineWidth = 10

let maskView = UIView(frame: self.view.frame)
maskView.backgroundColor = UIColor.black
maskView.layer.mask = maskLayer

blur.layer.addSublayer(borderLayer)
blur.mask = maskView

如果您有任何问题,请告诉我!


2
这对我帮助很大! - Gizmodo
1
天啊,我找了好一段时间才找到这个。运行得非常好! - aBikis
这太棒了。谢谢。 - Zack Shapiro

4

除了Jack的解决方案之外,如果您使用的是iOS >11,则只需将blur.layer.mask设置为maskLayer:

if #available(iOS 11.0, *) {
    blur.layer.mask = maskLayer
} else {
    let maskView = UIView(frame: self.view.frame)
    maskView.backgroundColor = UIColor.black
    maskView.layer.mask = borderLayer
    blur.mask = maskView
}

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