ios uiview mask

ios - Simplemente enmascara una vista con un rectángulo



uiview mask (6)

Quiero saber cómo simplemente enmascarar el área visible de una vista de cualquier tipo. Todas las respuestas / tutoriales que he leído hasta ahora describen el enmascaramiento con una imagen, degradado o creación de esquinas redondas, que es mucho más avanzado de lo que busco.

Ejemplo: Tengo un UIView con los límites (0, 0, 100, 100) y quiero cortar la mitad derecha de la vista con una máscara. Por lo tanto, mi marco de máscara sería (0, 0, 50, 100).

¿Alguna idea de cómo hacer esto simplemente? No quiero anular el método drawrect ya que esto debería ser aplicable a cualquier UIView.

He intentado esto pero solo hace que la vista sea invisible.

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


Una capa opcional cuyo canal alfa se usa como máscara para seleccionar entre el fondo de la capa y el resultado de la composición del contenido de la capa con el fondo filtrado.

@ propiedad (retener) CALayer * máscara

La forma correcta de hacer lo que quiere es crear el maskView del mismo marco (0, 0, 100, 100) como viewToMask que capa desea enmascarar. Luego debe configurar el clearColor para la ruta que desea hacer invisible (esto bloqueará la interacción de la vista sobre la ruta, así que tenga cuidado con la jerarquía de la vista).


Ejemplo muy simple en un Swift ViewController, basado en la respuesta aceptada:

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

Salida


Establecer MaskToBounds no es suficiente, por ejemplo, en el escenario en el que tiene UIImageView que está posicionado dentro de RelativeLayout . En caso de que coloque su UIImageView cerca del borde superior del diseño y luego gire su UIImageView , pasará sobre el diseño y no se recortará. Si establece ese indicador en verdadero, se recortará sí, pero también se recortará si UIImageView está en el centro del diseño, y eso no es lo que desea.

Entonces, determinar maskRect es el enfoque correcto.


Gracias al enlace de MSK, esta es la forma en que fui que funciona 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;


Gracias por las respuestas chicos.

En caso de que alguien no pueda encontrar la respuesta adecuada en SO para esta pregunta durante horas, como acabo de hacer, he reunido una UIView esencial en Swift 2.2 para masking / clipping UIView con 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 } }

Uso:

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)

Espero que le salve a alguien algún tiempo en el futuro :)


No necesita ninguna máscara en absoluto. Simplemente clipsToBounds en una vista de contenedor con el marco más pequeño y configure clipsToBounds .

wrapper.clipsToBounds = YES;