web-dev-qa-db-fra.com

Masquez simplement une vue UIV avec un rectangle

Je veux savoir comment masquer simplement la zone visible d'une UIView de toute sorte. Toutes les réponses/tutoriels que j'ai lus jusqu'à présent décrivent le masquage avec une image, un dégradé ou la création de coins ronds qui est beaucoup plus avancé que ce que je recherche.

Exemple: J'ai une UIView avec les limites (0, 0, 100, 100) et je veux couper la moitié droite de la vue en utilisant un masque. Par conséquent, mon cadre de masque serait (0, 0, 50, 100).

Une idée comment faire cela simplement? Je ne veux pas remplacer la méthode drawrect car cela devrait être applicable à tout UIView.

J'ai essayé cela, mais cela rend la vue entière invisible.

CGRect mask = CGRectMake(0, 0, 50, 100);
UIView *maskView = [[UIView alloc] initWithFrame:mask];
viewToMask.layer.mask = maskView.layer;
51
Accatyyc

Grâce au lien de MSK, c'est la voie que j'ai suivie qui fonctionne bien:

// Create a mask layer and the frame to determine what will be visible in the view.
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
CGRect maskRect = CGRectMake(0, 0, 50, 100);

// Create a path with the rectangle in it.
CGPathRef path = CGPathCreateWithRect(maskRect, NULL);

// Set the path to the mask layer.
maskLayer.path = path;

// Release the path since it's not covered by ARC.
CGPathRelease(path);

// Set the mask of the view.
viewToMask.layer.mask = maskLayer;
124
Accatyyc

Pas besoin de masque du tout. Il suffit de le placer dans une vue wrapper avec le plus petit cadre, et de définir clipsToBounds .

wrapper.clipsToBounds = YES;
20
Geri

Merci pour les réponses les gars.

Au cas où quelqu'un ne trouverait pas de réponse appropriée sur SO pour cette question pendant des heures, comme je viens de le faire, j'ai assemblé un Gist de travail dans Swift 2.2 pour masking/clippingUIView avec 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.append(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.append(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)

J'espère que cela fera gagner du temps à quelqu'un à l'avenir :)

20
Flar

Exemple très simple dans un Swift ViewController, basé sur la réponse acceptée:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let redView = UIView(frame: view.bounds)
        view.addSubview(redView)

        view.backgroundColor = UIColor.greenColor()
        redView.backgroundColor = UIColor.redColor()

        mask(redView, maskRect: CGRect(x: 50, y: 50, width: 50, height: 50))
    }

    func mask(viewToMask: UIView, maskRect: CGRect) {
        let maskLayer = CAShapeLayer()
        let path = CGPathCreateWithRect(maskRect, nil)
        maskLayer.path = path

        // Set the mask of the view.
        viewToMask.layer.mask = maskLayer;
    }
}

Sortie

enter image description here

2
Dan Rosenstark

Un calque facultatif dont canal alpha est utilisé comme masque pour sélectionner entre l'arrière-plan du calque et le résultat de la composition du contenu du calque avec son arrière-plan filtré.

@property (conserver) masque CALayer *

La bonne façon de faire ce que vous voulez est de créer le maskView du même cadre (0, 0, 100, 100) que le viewToMask quel calque vous voulez masquer. Ensuite, vous devez définir clearColor pour le chemin que vous souhaitez rendre invisible (cela bloquera l'interaction de la vue sur le chemin, alors soyez prudent avec la hiérarchie des vues).

1
A-Live

Swift 5, merci @Dan Rosenstark

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

extension UIView{
    func mask(_ rect: CGRect){
        let mask = CAShapeLayer()
        let path = CGPath(rect: rect, transform: nil)
        mask.path = path
        // Set the mask of the view.
        layer.mask = mask
    }
}
0
dengST30