clip-masking uiview with CAShapeLayer and UIBezierPath

后端 未结 3 798
轻奢々
轻奢々 2021-01-04 21:10

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

相关标签:
3条回答
  • 2021-01-04 21:44

    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
        }
    }
    
    0 讨论(0)
  • 2021-01-04 21:46

    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
    
    0 讨论(0)
  • 2021-01-04 21:57

    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 :)

    0 讨论(0)
提交回复
热议问题