Saltar al contenido

Ronda de dos esquinas en UIView

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.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *