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;