1

I have an UIVisualEffectView and a shape (CGPath) that I want to view's shape to be.

I've heard that masking the UIVisualEffectView will do it.

So that what I did (PocketSVG is an API that helps you convert SVG file to CGPath). code:

let blur: UIBlurEffect = UIBlurEffect(style: .Light)
let ev: UIVisualEffectView = UIVisualEffectView(effect: blur)
ev.frame = self.frame
ev.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(ev)

ev.rightAnchor.constraintEqualToAnchor(self.rightAnchor).active = true
ev.bottomAnchor.constraintEqualToAnchor(self.bottomAnchor).active = true
ev.leftAnchor.constraintEqualToAnchor(self.leftAnchor).active = true
ev.heightAnchor.constraintEqualToAnchor(self.heightAnchor, multiplier: 1.5).active = true

let myPath: CGPathRef = PocketSVG.pathFromSVGFileNamed("CategoriesBar").takeUnretainedValue()
var transform: CGAffineTransform = CGAffineTransformMakeScale(self.frame.size.width / 754.0, self.frame.size.height / 220.0)

let transformedPath: CGPathRef = CGPathCreateMutableCopyByTransformingPath(myPath, &transform)!

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

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

ev.maskView = maskView

It works great on iOS 9 and below but it doesn't work on iOS 10 and Xcode 8 (there is no blur, just transparent view).

Here's a link for my SVG file if someone wants to try:

https://www.dropbox.com/s/mjql2bzf37vpl2r/CategoriesBar.svg?dl=0

Any idea how can I make it work on iOS 10 as well?

Thanks!

FS.O6
  • 1,394
  • 2
  • 20
  • 42
  • You are setting the frame of the visual effects view to `self.bounds`, but setting the mask view frame to `self.frame`. See if that is the cause. `UIVisualEffectView` is known to have buggy behavior when masking. – Léo Natan Oct 23 '16 at 09:20
  • @LeoNatan I've tried to set both to `self.bounds` and `self.frame` and it still doesn't work :(.... – FS.O6 Oct 23 '16 at 09:24
  • @LeoNatan Any other idea? – FS.O6 Oct 23 '16 at 09:28
  • Sorry, not right now. – Léo Natan Oct 23 '16 at 09:32
  • Where do you call this code from, eg. `viewDidLoad` or `viewWillAppear`? If so, `view.frame` and `view.bounds` will contain invalid values such as (0, 0, 1000, 1000) as the views haven't been layouted yet. Check it in the debugger. – Codo Oct 23 '16 at 09:36
  • @Codo I'm calling it in `layoutSubviews()` (it's a `UIView`). And I'm adding the view as subview and settings its constraints in `viewDidLoad()` – FS.O6 Oct 23 '16 at 09:37
  • @Codo I've checked: `self.frame` - `(0.0, 553.5, 375.0, 113.5)`, `self.bounds` - `(0.0, 0.0, 375.0, 113.5)` – FS.O6 Oct 23 '16 at 09:39
  • @Codo Even if I create a regular `UIView` and settings its `maskView` property to the mask view it doesn't work (`theView.layer.mask = maskLayer` does work). Maybe its relates? – FS.O6 Oct 23 '16 at 09:50
  • @LeoNatan Even if I create a regular `UIView` and settings its `maskView` property to the mask view it doesn't work (`theView.layer.mask = maskLayer` does work). Maybe its relates? – FS.O6 Oct 23 '16 at 09:51
  • Mask layer does not work with `UIVisualEffectView`. Make sure you have set up your mask view correctly. UIKit uses the alpha channel to mask views. @FS.O6 – Léo Natan Oct 23 '16 at 09:53
  • @LeoNatan Yes I know maskLayer won't work on a blur view, but mask view doesn't work even on a regular view. and what do you mean by "Make sure you have set up your mask view correctly. UIKit uses the alpha channel to mask views.", what should I check? Thanks!! – FS.O6 Oct 23 '16 at 09:55
  • Instead of adding your visual effects view, add the mask view to the hierarchy and see if there is transparency. If you see black and white, this is no good. – Léo Natan Oct 23 '16 at 09:56
  • @LeoNatan Do you mean `self.addSubview(maskView)`? – FS.O6 Oct 23 '16 at 09:58
  • Right. This way you can see how the mask view looks like. – Léo Natan Oct 23 '16 at 09:59
  • @LeoNatan OK, it's black, but probably because `maskView.backgroundColor = UIColor.blackColor()` – FS.O6 Oct 23 '16 at 10:00
  • Cool. Set it to clear color and see. Only your path should have color. – Léo Natan Oct 23 '16 at 10:01
  • @LeoNatan My path doesn't have `FillColor`, should I set `fillColor` to my path? – FS.O6 Oct 23 '16 at 10:01
  • Yes, set a fill color. – Léo Natan Oct 23 '16 at 10:02
  • @LeoNatan `maskLayer.fillColor = UIColor.blueColor().CGColor`? – FS.O6 Oct 23 '16 at 10:04
  • @LeoNatan I've set a fill color to the maskLayer and I don't see it – FS.O6 Oct 23 '16 at 10:05
  • Need to check your shape layer. I am not very familiar with that API. Check that the path is correct and the fill rule. – Léo Natan Oct 23 '16 at 10:09
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/126441/discussion-between-fs-o6-and-leo-natan). – FS.O6 Oct 23 '16 at 10:11

1 Answers1

0

There is a known bug when using layer.mask in iOS 10 / Xcode 8 unfortunately re masking VisualEffectViews. I found a code sample in the accepted answer here that should work for you...it seems to differ from your code only by the Swift 3 syntax (as far as I could see). It could be worth worth double checking the order of code events and the syntax you are using, though, just to be sure you aren't missing anything.

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

You could also try forcing a view layout using setNeedsDisplay() and layoutIfNeeded() after creating your mask. See the comment by flainez on Aug 4th on this thread on the apple developer forums, who said that this fixed his issue with displaying a masked VisualEffectView.

The linked thread above also has extensive discussion about this issue, code samples and feedback and suggestions from an Apple employee, 'Rincewind' re fixing this issue. I would recommend reading through it if you're still struggling with this issue. I think the overall consensus is that the issue is resolvable for masked VisualEffectsViews, but was not resolvable for developers trying to use masked VisualEffectsViews during transitions between views.

You could also check out this 2015 WWDC video about UIVisualEffectView.

Community
  • 1
  • 1
Natalia
  • 1,308
  • 16
  • 23