iOS invert mask in drawRect

前端 未结 7 2004
名媛妹妹
名媛妹妹 2020-12-08 07:54

With the code below, I am successfully masking part of my drawing, but it\'s the inverse of what I want masked. This masks the inner portion of the drawing, where I would li

相关标签:
7条回答
  • 2020-12-08 08:17

    For Swift 4.2

    func mask(viewToMask: UIView, maskRect: CGRect, invert: Bool = false) {
        let maskLayer = CAShapeLayer()
        let path = CGMutablePath()
        if (invert) {
            path.addRect(viewToMask.bounds)
        }
        path.addRect(maskRect)
    
        maskLayer.path = path
        if (invert) {
            maskLayer.fillRule = .evenOdd
        }
    
        // Set the mask of the view.
        viewToMask.layer.mask = maskLayer;
    }
    
    0 讨论(0)
  • 2020-12-08 08:18

    With even odd filling on the shape layer (maskLayer.fillRule = kCAFillRuleEvenOdd;) you can add a big rectangle that covers the entire frame and then add the shape you are masking out. This will in effect invert the mask.

    CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
    CGMutablePathRef maskPath = CGPathCreateMutable();
    CGPathAddRect(maskPath, NULL, someBigRectangle); // this line is new
    CGPathAddPath(maskPath, nil, myPath.CGPath);
    [maskLayer setPath:maskPath];
    maskLayer.fillRule = kCAFillRuleEvenOdd;         // this line is new
    CGPathRelease(maskPath);
    self.layer.mask = maskLayer;
    
    0 讨论(0)
  • 2020-12-08 08:20

    Swift 5

    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            let red = UIView(frame: view.bounds)
            view.addSubview(red)
            view.backgroundColor = UIColor.cyan
            red.backgroundColor = UIColor.red
            red.mask(CGRect(x: 50, y: 50, width: 50, height: 50), invert: true)
        }
    }
    
    extension UIView{
    
        func mask(_ rect: CGRect, invert: Bool = false) {
            let maskLayer = CAShapeLayer()
            let path = CGMutablePath()
            if (invert) {
                path.addRect(bounds)
            }
            path.addRect(rect)
            maskLayer.path = path
            if (invert) {
                maskLayer.fillRule = CAShapeLayerFillRule.evenOdd
            }
            // Set the mask of the view.
            layer.mask = maskLayer
        }
    }
    

    Thanks @arvidurs

    0 讨论(0)
  • 2020-12-08 08:27

    In order to invert mask you can to something like this

    1. Here I have mask of crossed rectancles like

       let crossPath =  UIBezierPath(rect: cutout.insetBy(dx: 30, dy: -5))
                crossPath.append(UIBezierPath(rect: cutout.insetBy(dx: -5, dy: 30)))
                  let crossMask = CAShapeLayer()
                  crossMask.path = crossPath.cgPath
                  crossMask.backgroundColor = UIColor.clear.cgColor
                  crossMask.fillRule = .evenOdd
      
    2. And here I add 3rd rectancle around my crossed rectancles so using .evenOdd it takes area that is equal to (New Rectancle - Old Crossed Rectangle) so in other words outside area of crossed rectancles

        let crossPath = UIBezierPath(rect: cutout.insetBy(dx: -5, dy: -5) )
          crossPath.append(UIBezierPath(rect: cutout.insetBy(dx: 30, dy: -5)))
          crossPath.append(UIBezierPath(rect: cutout.insetBy(dx: -5, dy: 30)))
          let crossMask = CAShapeLayer()
          crossMask.path = crossPath.cgPath
          crossMask.backgroundColor = UIColor.clear.cgColor
          crossMask.fillRule = .evenOdd
      

    0 讨论(0)
  • 2020-12-08 08:33

    For Swift 3.0

    func mask(viewToMask: UIView, maskRect: CGRect, invert: Bool = false) {
        let maskLayer = CAShapeLayer()
        let path = CGMutablePath()
        if (invert) {
            path.addRect(viewToMask.bounds)
        }
        path.addRect(maskRect)
    
        maskLayer.path = path
        if (invert) {
            maskLayer.fillRule = kCAFillRuleEvenOdd
        }
    
        // Set the mask of the view.
        viewToMask.layer.mask = maskLayer;
    }
    
    0 讨论(0)
  • 2020-12-08 08:34

    Based on the accepted answer, here's another mashup in Swift. I've made it into a function and made the invert optional

    class func mask(viewToMask: UIView, maskRect: CGRect, invert: Bool = false) {
        let maskLayer = CAShapeLayer()
        let path = CGPathCreateMutable()
        if (invert) {
            CGPathAddRect(path, nil, viewToMask.bounds)
        }
        CGPathAddRect(path, nil, maskRect)
    
        maskLayer.path = path
        if (invert) {
            maskLayer.fillRule = kCAFillRuleEvenOdd
        }
    
        // Set the mask of the view.
        viewToMask.layer.mask = maskLayer;
    }
    
    0 讨论(0)
提交回复
热议问题