I have a problem clipping a view using CAShapeLayer-UIBezierPath , I want to clip the content but I end up getting a stroke (frame) with that UIBezierPath , This is my code
You can even improve @Eugene's response (greate work, mate!) with corner radius
extension UIView {
func mask(withRect rect: CGRect, cornerRadius: CGFloat = 0, inverse: Bool = false) {
let path = cornerRadius > 0 ?
UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius) :
UIBezierPath(rect: rect)
let maskLayer = CAShapeLayer()
if inverse {
path.append(UIBezierPath(rect: bounds))
maskLayer.fillRule = kCAFillRuleEvenOdd
}
maskLayer.path = path.cgPath
self.layer.mask = maskLayer
}
}
as rob mayoff said You can do this easily by setting your view's layer mask to a CAShapeLayer.
UIBezierPath *myClippingPath = ...
CAShapeLayer *mask = [CAShapeLayer layer];
mask.path = myClippingPath.CGPath;
myView.layer.mask = mask;
In Swift
let myClippingPath = UIBezierPath( ... )
let mask = CAShapeLayer()
mask.path = myClippingPath.CGPath
myView.layer.mask = mask
Thanks for answers guys.
In case someone can't find suitable answer on SO for this question for hours, like i just did, i've assembled a working gist in Swift 2.2 for masking/clipping UIView with CGRect/UIBezierPath:
https://gist.github.com/Flar49/7e977e81f1d2827f5fcd5c6c6a3c3d94
extension UIView {
func mask(withRect rect: CGRect, inverse: Bool = false) {
let path = UIBezierPath(rect: rect)
let maskLayer = CAShapeLayer()
if inverse {
path.appendPath(UIBezierPath(rect: self.bounds))
maskLayer.fillRule = kCAFillRuleEvenOdd
}
maskLayer.path = path.CGPath
self.layer.mask = maskLayer
}
func mask(withPath path: UIBezierPath, inverse: Bool = false) {
let path = path
let maskLayer = CAShapeLayer()
if inverse {
path.appendPath(UIBezierPath(rect: self.bounds))
maskLayer.fillRule = kCAFillRuleEvenOdd
}
maskLayer.path = path.CGPath
self.layer.mask = maskLayer
}
}
Usage:
let viewSize = targetView.bounds.size
let rect = CGRect(x: 20, y: 20, width: viewSize.width - 20*2, height: viewSize.height - 20*2)
// Cuts rectangle inside view, leaving 20pt borders around
targetView.mask(withRect: rect, inverse: true)
// Cuts 20pt borders around the view, keeping part inside rect intact
targetView.mask(withRect: rect)
Hope it will save someone some time in the future :)