Este team especializado despúes de días de trabajo y de recopilar de datos, encontramos la solución, nuestro deseo es que todo este artículo sea de utilidad para tu proyecto.
Solución:
CACornerMask introducido en iOS 11, que ayuda a definir la capa superior izquierda, derecha, izquierda e inferior derecha en la vista. A continuación se muestra un ejemplo para usar.
Aquí trato de redondear solo dos esquinas superiores:
myView.clipsToBounds = true
myView.layer.cornerRadius = 10
myView.layer.maskedCorners = [.layerMinXMinYCorner,.layerMaxXMinYCorner]
FYI Ref:
que yo sepa, si también necesita enmascarar las subvistas, puede utilizar CALayer
enmascaramiento. Hay dos formas de hacer esto. El primero es un poco más elegante, el segundo es una solución alternativa 🙂 pero también es rápido. Ambos se basan en CALayer
enmascaramiento. Usé ambos métodos en un par de proyectos el año pasado, entonces espero que encuentres algo útil.
Solucion 1
En primer lugar, creé esta función para generar una máscara de imagen sobre la marcha (UIImage
) con la esquina redondeada que necesito. Esta función necesita esencialmente 5 parámetros: los límites de la imagen y el radio de 4 esquinas (arriba a la izquierda, arriba a la derecha, abajo a la izquierda y abajo a la derecha).
static inline UIImage* MTDContextCreateRoundedMask( CGRect rect, CGFloat radius_tl, CGFloat radius_tr, CGFloat radius_bl, CGFloat radius_br )
CGContextRef context;
CGColorSpaceRef colorSpace;
colorSpace = CGColorSpaceCreateDeviceRGB();
// create a bitmap graphics context the size of the image
context = CGBitmapContextCreate( NULL, rect.size.width, rect.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast );
// free the rgb colorspace
CGColorSpaceRelease(colorSpace);
if ( context == NULL )
return NULL;
// cerate mask
CGFloat minx = CGRectGetMinX( rect ), midx = CGRectGetMidX( rect ), maxx = CGRectGetMaxX( rect );
CGFloat miny = CGRectGetMinY( rect ), midy = CGRectGetMidY( rect ), maxy = CGRectGetMaxY( rect );
CGContextBeginPath( context );
CGContextSetGrayFillColor( context, 1.0, 0.0 );
CGContextAddRect( context, rect );
CGContextClosePath( context );
CGContextDrawPath( context, kCGPathFill );
CGContextSetGrayFillColor( context, 1.0, 1.0 );
CGContextBeginPath( context );
CGContextMoveToPoint( context, minx, midy );
CGContextAddArcToPoint( context, minx, miny, midx, miny, radius_bl );
CGContextAddArcToPoint( context, maxx, miny, maxx, midy, radius_br );
CGContextAddArcToPoint( context, maxx, maxy, midx, maxy, radius_tr );
CGContextAddArcToPoint( context, minx, maxy, minx, midy, radius_tl );
CGContextClosePath( context );
CGContextDrawPath( context, kCGPathFill );
// Create CGImageRef of the main view bitmap content, and then
// release that bitmap context
CGImageRef bitmapContext = CGBitmapContextCreateImage( context );
CGContextRelease( context );
// convert the finished resized image to a UIImage
UIImage *theImage = [UIImage imageWithCGImage:bitmapContext];
// image is retained by the property setting above, so we can
// release the original
CGImageRelease(bitmapContext);
// return the image
return theImage;
Ahora solo necesitas unas pocas líneas de código. Pongo cosas en mi viewController viewDidLoad
método porque es más rápido, pero también puede usarlo en su UIView
con el layoutSubviews
método en el ejemplo.
- (void)viewDidLoad
// Create the mask image you need calling the previous function
UIImage *mask = MTDContextCreateRoundedMask( self.view.bounds, 50.0, 50.0, 0.0, 0.0 );
// Create a new layer that will work as a mask
CALayer *layerMask = [CALayer layer];
layerMask.frame = self.view.bounds;
// Put the mask image as content of the layer
layerMask.contents = (id)mask.CGImage;
// set the mask layer as mask of the view layer
self.view.layer.mask = layerMask;
// Add a backaground color just to check if it works
self.view.backgroundColor = [UIColor redColor];
// Add a test view to verify the correct mask clipping
UIView *testView = [[UIView alloc] initWithFrame:CGRectMake( 0.0, 0.0, 50.0, 50.0 )];
testView.backgroundColor = [UIColor blueColor];
[self.view addSubview:testView];
[testView release];
[super viewDidLoad];
Solucion 2
Esta solución es un poco más “sucia”. Básicamente, podría crear una capa de máscara con la esquina redondeada que necesita (todas las esquinas). Luego, debe aumentar la altura de la capa de máscara por el valor del radio de la esquina. De esta forma se ocultan las esquinas redondeadas inferiores y solo se puede ver la esquina redondeada superior. Puse el código solo en el viewDidLoad
método porque es más rápido, pero también puede usarlo en su UIView
con el layoutSubviews
método en el ejemplo.
- (void)viewDidLoad
// set the radius
CGFloat radius = 50.0;
// set the mask frame, and increase the height by the
// corner radius to hide bottom corners
CGRect maskFrame = self.view.bounds;
maskFrame.size.height += radius;
// create the mask layer
CALayer *maskLayer = [CALayer layer];
maskLayer.cornerRadius = radius;
maskLayer.backgroundColor = [UIColor blackColor].CGColor;
maskLayer.frame = maskFrame;
// set the mask
self.view.layer.mask = maskLayer;
// Add a backaground color just to check if it works
self.view.backgroundColor = [UIColor redColor];
// Add a test view to verify the correct mask clipping
UIView *testView = [[UIView alloc] initWithFrame:CGRectMake( 0.0, 0.0, 50.0, 50.0 )];
testView.backgroundColor = [UIColor blueColor];
[self.view addSubview:testView];
[testView release];
[super viewDidLoad];
Espero que esto ayude. ¡Ciao!
Revisando las pocas respuestas y comentarios, descubrí que al usar UIBezierPath bezierPathWithRoundedRect
y CAShapeLayer
la forma más sencilla y directa. Puede que no sea apropiado para casos muy complejos, pero para el redondeo ocasional de esquinas, funciona rápido y sin problemas para mí.
Había creado un ayudante simplificado que establece la esquina apropiada en la máscara:
-(void) setMaskTo:(UIView*)view byRoundingCorners:(UIRectCorner)corners
UIBezierPath* rounded = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(10.0, 10.0)];
CAShapeLayer* shape = [[CAShapeLayer alloc] init];
[shape setPath:rounded.CGPath];
view.layer.mask = shape;
Para usarlo, simplemente llame con la enumeración UIRectCorner apropiada, por ejemplo:
[self setMaskTo:self.photoView byRoundingCorners:UIRectCornerTopLeft|UIRectCornerBottomLeft];
Tenga en cuenta que, para mí, lo uso para redondear las esquinas de las fotos en un UITableViewCell agrupado, el radio de 10.0 funciona bien para mí, si solo necesito cambiar el valor según corresponda.
EDITAR: solo observe una respuesta anterior muy similar a esta (enlace). Aún puede usar esta respuesta como una función de conveniencia adicional si es necesario.
EDITAR: Mismo código que la extensión UIView en Swift 3
extension UIView
func maskByRoundingCorners(_ masks:UIRectCorner, withRadii radii:CGSize = CGSize(width: 10, height: 10))
let rounded = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: masks, cornerRadii: radii)
let shape = CAShapeLayer()
shape.path = rounded.cgPath
self.layer.mask = shape
Para usarlo, simple llamada maskByRoundingCorner
en cualquier UIView
:
view.maskByRoundingCorners([.topLeft, .bottomLeft])
Al final de todo puedes encontrar las críticas de otros creadores, tú incluso eres capaz dejar el tuyo si lo deseas.