10

I'm making a custom control circle. Part of the circle may be transparent. It would make more visual sense and look better if it was translucent instead of transparent.

Because views are rectangular, and I only want the circle to be translucent, not the rest of the rectangle, this is a problem.

The UIVisualEffectView is behind the custom control.

enter image description here

(Without anything rendered inside of the circle for debugging purposes)

As you can see, the view is blurring things outside of the circle.

I don't know how to blur inside only the view, and the prerelease documentation is practically empty. My only thought is to create many 1x1 views to cover the circle, but this seems like it would not really work, and even if it did it would be a slow and ugly solution. How can I blur the content inside the view, without blurring anything outside it?

Eliza Wilson
  • 1,031
  • 1
  • 13
  • 38

1 Answers1

30

Set the circle view's layer mask to a filled circle:

CircleControlView *circleView = yourCircleView();

CAShapeLayer *mask = [CAShapeLayer layer];
mask.path = [UIBezierPath bezierPathWithOvalInRect:circleView.bounds].CGPath;
circleView.layer.mask = mask;

UPDATE

Swift playground example:

import UIKit
import XCPlayground
import QuartzCore

UIGraphicsBeginImageContext(CGSize(width: 100, height: 100))
let viewPath = UIBezierPath(ovalInRect:CGRect(x:1,y:1,width:98,height:98))
viewPath.lineWidth = 2
viewPath.stroke()
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

let view = UIView(frame:CGRect(x:0,y:0,width:100,height:100))
XCPShowView("view", view)

let label = UILabel(frame:view.bounds)
label.text = "This is the text in the background behind the circle."
label.numberOfLines = 0
view.addSubview(label)

let effectView = UIVisualEffectView(effect:UIBlurEffect(style:.ExtraLight))
effectView.frame = view.bounds
view.addSubview(effectView)

let circleView = UIImageView(image:image)
effectView.addSubview(circleView)

let maskPath = UIBezierPath(ovalInRect:circleView.bounds)
let mask = CAShapeLayer()
mask.path = maskPath.CGPath
effectView.layer.mask = mask

Result:

translucent circle

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Worth a quick note – I've only been able to get this to work when the UIVisualEffectView has **vibrancy disabled**. If I turn on vibrancy, the mask is apparently ignored. – Benjohn Sep 26 '14 at 10:00
  • 1
    @Benjohn My circle-shaped mask still works fine when the visual effect view has vibrancy enabled. It seems weird that your mask wouldn't work when vibrancy is enabled. I think it must be caused by something else. – Eliza Wilson Nov 05 '14 at 01:49
  • Hi @E.A.Wilson thanks – you're right, I was using vibrancy wrong :-) – Benjohn Nov 05 '14 at 11:28
  • Can this be done with a different image? Say I have an image of an arrow and I want the effects of a UIEffectsView to be applied only to the image. How would I apply this code to that? – Jacob Feb 19 '16 at 01:53
  • I don't understand what you're asking for, but it sounds different enough that it should be a separate question. – rob mayoff Feb 19 '16 at 02:01