Ilya Ilya - 1 month ago 18
Swift Question

space between two circles when one cuts another

I need to arrange two

UIImageView
s in the following way, where one cuts another with some space inbetween each other as shown in the following example:

space circles

I can't use
borderWidth
because I need transparency around the green circle. There is a background image view in my app, so with the
borderWidth
users would see a black border line around the image or they would see nothing if I use
clearColor
. Any suggestions?

Answer

You can use a layer mask to achieve this.

Swift 2.3

let mask = CAShapeLayer()
let path = CGPathCreateMutable()

let center = view.convertPoint(statusImageView.center, toView: profileImageView)
let radius = statusImageView.frame.width / 2 + 4

CGPathAddRect(path, nil, profileImageView.bounds)
CGPathAddArc(path, nil, center.x, center.y, radius, 0, CGFloat(2 * M_PI), false)

mask.fillRule = kCAFillRuleEvenOdd
mask.path = path

profileImageView.layer.mask = mask
profileImageView.clipsToBounds = true

Swift 3

let mask = CAShapeLayer()
let path = CGMutablePath()

path.addRect(profileImageView.bounds)
path.addArc(
    center: view.convert(statusImageView.center, to: profileImageView),
    radius: statusImageView.frame.width / 2 + 4,
    startAngle: 0,
    endAngle: CGFloat(2 * M_PI),
    clockwise: false
)

mask.fillRule = kCAFillRuleEvenOdd
mask.path = path

profileImageView.layer.mask = mask
profileImageView.clipsToBounds = true

UPDATE

class MatchViewController: UIViewController {

    // MARK: Outlets

    @IBOutlet var matchedImageView: UIImageView!
    @IBOutlet var profileImageView: UIImageView!
    @IBOutlet var tickImageView: UIImageView!

    // MARK: Properties

    var innerContainer: UIView! { return profileImageView.superview }
    var outerContainer: UIView! { return innerContainer?.superview }

    // MARK: Lifecycle

    override func preferredStatusBarStyle() -> UIStatusBarStyle { return .LightContent }

    override func viewDidAppear(animated: Bool) {

        super.viewDidAppear(animated)

        let mask = CAShapeLayer(),
            path = CGPathCreateMutable()

        let center = outerContainer.convertPoint(tickImageView.center, toView: innerContainer),
            radius = tickImageView.frame.width / 2 + 4

        CGPathAddRect(path, nil, innerContainer.bounds)
        CGPathAddArc(path, nil, center.x, center.y, radius, 0, CGFloat(2 * M_PI), false)

        mask.fillRule = kCAFillRuleEvenOdd
        mask.path = path

        innerContainer?.layer.mask = mask
        innerContainer?.clipsToBounds = true
    }
}

Make sure your views are structured like this.

Storyboard

This should be the result. Should be.

Simulator

Comments