3

I'm working with Xcode 8 and Swift 2.3
Starting from this nice post and my own question, I can get this two distinct effects, but I can't "join" it.

enter image description here:

First one (blur):

internal extension UIView {

    /**
     Add and display on current view a blur effect.
     */
    internal func addBlurEffect(style style: UIBlurEffectStyle = .ExtraLight, atPosition position: Int = -1) -> UIView {
        // Blur Effect
        let blurEffectView = self.createBlurEffect(style: style)
        if position >= 0 {
            self.insertSubview(blurEffectView, atIndex: position)
        } else {
            self.addSubview(blurEffectView)
        }
        return blurEffectView
    }

    internal func createBlurEffect(style style: UIBlurEffectStyle = .ExtraLight) -> UIView {
        let blurEffect = UIBlurEffect(style: style)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)
        blurEffectView.frame = self.bounds
        blurEffectView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        return blurEffectView
    }

}

Second one (radial gradient):

public class BlurFilterMask: CAShapeLayer {

    // MARK: - Public properties -

    public var origin: CGPoint = CGPointZero
    public var diameter: CGFloat = 0.0
    public var gradientWidth: CGFloat = 200.0
    public var gradientColorOpacity: CGFloat = 0.5

    // MARK: - Layout -

    override public func drawInContext(ctx: CGContext) {
        let clearRegionRadius = self.diameter * 0.5
        let blurRegionRadius = clearRegionRadius + self.gradientWidth

        let baseColorSpace = CGColorSpaceCreateDeviceRGB()

        let colours: [CGFloat] = [0.0, 0.0, 0.0, 0.0,     // Clear region
                                  0.0, 0.0, 0.0, self.gradientColorOpacity] // blur region color
        let colourLocations: [CGFloat] = [0.0, 0.4]
        let gradient = CGGradientCreateWithColorComponents (baseColorSpace, colours, colourLocations, 2)
        CGContextDrawRadialGradient(ctx, gradient!, self.origin, clearRegionRadius, self.origin, blurRegionRadius, .DrawsAfterEndLocation)
    }
}

Any tips would be appreciated!

Community
  • 1
  • 1
Luca Davanzo
  • 21,000
  • 15
  • 120
  • 146
  • didn't you ask a very similar question recently? http://stackoverflow.com/questions/40256942/draw-hole-on-uiblureffect/40401855#40401855 – d.felber Nov 08 '16 at 08:26
  • Similar, I can't apply a radial gradient on the hole... I tried with all possible combinations! – Luca Davanzo Nov 08 '16 at 08:31

1 Answers1

0

I did it!

Notice that self is a mask UIView added on top of hierarchy.

func setupBlur(frame frame: CGRect, center: CGPoint, diameter: CGFloat) {

    self.blurFilterMask = BlurFilterMask()
    self.blurFilterMask.diameter = diameter
    self.blurFilterMask.frame = self.frame
    self.blurFilterMask.origin = center
    self.blurFilterMask.shouldRasterize = true
    self.layer.addSublayer(self.blurFilterMask)
    self.blurFilterMask.setNeedsDisplay()

    self.viewBlur = self.addBlurEffect(style: self.blurEffectStyle, atPosition: 0)

    self.holePath = self.getHolePath(frame: frame, center: center, diameter: diameter)

    self.addMaskOnBlurView(self.holePath, center: center, diameter: diameter)

}

func addMaskOnBlurView(holePath: UIBezierPath, center: CGPoint, diameter: CGFloat?) -> UIView {
    let maskView = UIView(frame: self.viewBlur!.bounds)
    maskView.clipsToBounds = true
    maskView.backgroundColor = UIColor.clearColor()

    let blurFilterMask = ERBlurFilterMask()
    blurFilterMask.diameter = diameter ?? 10
    blurFilterMask.frame = self.frame
    blurFilterMask.origin = center
    blurFilterMask.shouldRasterize = true
    blurFilterMask.gradientColorOpacity = 1

    maskView.layer.addSublayer(blurFilterMask)
    blurFilterMask.setNeedsDisplay()

    self.viewBlur!.maskView = maskView
    return maskView
}

Summarizing:

  • create mask view as overlay, call it A
  • add blur filter mask on A's layers
  • create blur view, call it B, and append on top
  • create another view, call it C, and add another filter mask
  • apply C as maskView of B

I don't know if this is THE solution, but it worked for me. If anyone have another better solution please share it!

Luca Davanzo
  • 21,000
  • 15
  • 120
  • 146