web-dev-qa-db-ja.com

drawRectのiOS反転マスク

以下のコードを使用すると、描画の一部を正常にマスクできますが、これはマスクしたいものの逆です。これにより、図面の内側の部分がマスクされ、外側の部分がマスクされます。このマスクを反転する簡単な方法はありますか?

以下のmyPathUIBezierPathです。

CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
CGMutablePathRef maskPath = CGPathCreateMutable();
CGPathAddPath(maskPath, nil, myPath.CGPath);
[maskLayer setPath:maskPath];
CGPathRelease(maskPath);
self.layer.mask = maskLayer;
24
Mrwolfy

シェイプレイヤーに奇数の塗りつぶしがあります(maskLayer.fillRule = kCAFillRuleEvenOdd;)フレーム全体をカバーする大きな長方形を追加してから、マスクする形状を追加できます。これにより、事実上マスクが反転します。

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;
38

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;
}
17
arvidurs

受け入れられた回答に基づいて、Swiftの別のマッシュアップがあります。私はそれを関数にし、invertをオプションにしました

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;
}
8
Dan Rosenstark

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;
}
2
Kyle Milloy

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
    }
}

666

ありがとう@arvidurs

2
dengST30

これが私のSwift 4.2のソリューションでコーナー半径を許可します

extension UIView {

    func mask(withRect maskRect: CGRect, cornerRadius: CGFloat, inverse: Bool = false) {
        let maskLayer = CAShapeLayer()
        let path = CGMutablePath()
        if (inverse) {
            path.addPath(UIBezierPath(roundedRect: self.bounds, cornerRadius: cornerRadius).cgPath)
        }
        path.addPath(UIBezierPath(roundedRect: maskRect, cornerRadius: cornerRadius).cgPath)

        maskLayer.path = path
        if (inverse) {
            maskLayer.fillRule = CAShapeLayerFillRule.evenOdd
        }

        self.layer.mask = maskLayer;
    }

}
1
SamB

マスクを反転するには、次のようにすることができます

  1. ここに私は次のような交差した長方形のマスクを持っています

     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. そして、ここで交差した長方形の周りに3番目の長方形を追加するので、.evenOddを使用すると、(新しい長方形-古い交差した長方形)に等しい面積が必要になります。つまり、交差した長方形の領域の外側になります。

      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
    

enter image description here

0
Michał Ziobro