Ronda de dos esquinas en UIView

82

Hace un tiempo publiqué una pregunta sobre redondear solo dos esquinas de una vista y obtuve una gran respuesta, pero tengo problemas para implementarla. Aquí está mi método drawRect:

- (void)drawRect:(CGRect)rect {
    //[super drawRect:rect]; <------Should I uncomment this?
    int radius = 5;
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextBeginPath(context);
    CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, radius, M_PI, M_PI / 2, 1);
    CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1);
    CGContextClosePath(context);
    CGContextClip(context);
}

Se está llamando al método, pero no parece afectar el resultado de la vista. ¿Alguna idea de por qué?

Jumhyn
fuente

Respuestas:

103

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:

SachinVsSachin
fuente
Esta parece la forma idiomática de hacer esto ahora. ¡Buena atrapada!
Jumhyn
2
Tenga en cuenta que el ancho / alto de la vista aún debe ser al menos el doble del radio de la esquina, o aparecerán artefactos extraños. por ejemplo, redondeando solo las esquinas inferiores, un radio de 20 y una altura de solo 30 dan como resultado una celda visiblemente más estrecha (en uno o dos píxeles).
Graham Perks
Tenga en cuenta que esta es la forma correcta si su vista cambia su marco (posible debido a una UITextView en expansión, como en mi caso - stackoverflow.com/questions/50926215/… ). Si configura un UIBezierPath, no se actualizará automáticamente cuando cambie el marco.
thomers
Observó que solo está disponible desde iOS 11 y superiorif #available(iOS 11.0, *) { }
Tri Ngo Minh
2
Gran respuesta. Resulta clipsToBoundsque trueno es necesario configurarlo . Puede enmascarar las esquinas y agregar sombra a la capa cuando clipsToBoundsesté false. Fue muy útil para mí.
Au Ris
72


Hasta donde yo sé, si también necesita enmascarar las subvistas, puede usar CALayerenmascaramiento. 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 CALayerenmascaramiento. Usé ambos métodos en un par de proyectos el año pasado, entonces espero que encuentres algo útil.

Solución 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. Puse cosas en mi viewDidLoadmétodo viewController porque es más rápido, pero también puede usarlo en su costumbre UIViewcon el layoutSubviewsmé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 viewDidLoadmétodo porque es más rápido, pero también puede usarlo en su costumbre UIViewcon el layoutSubviewsmé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!

lomanf
fuente
¡Finalmente funcionó! ¡Muchas gracias! ¿Cuál es la ventaja de uno sobre el otro?
Jumhyn
De todos modos, incluso la solución CAShapeLayer es perfecta. Puede dibujar CGPath usando UIBezierPath (que necesita 3.2+) o simplemente con los métodos CGPath (CGPathMoveToPoint, CGPathAddQuadCurveToPoint, etc.)
lomanf
1
¿Cómo hago para que la máscara se redimensione automáticamente después de la rotación de vertical a horizontal?
chourobin
No olvide agregar layer.masksToBounds = YES
Dmitry Salnikov
¿Cómo puedo redondear solo las esquinas superior e inferior derecha?
PLOW
69

Revisando las pocas respuestas y comentarios, descubrí que el uso UIBezierPath bezierPathWithRoundedRecty CAShapeLayerla forma más simple y directa. Puede que no sea apropiado para casos muy complejos, pero para redondeos ocasionales 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 una UITableViewCell agrupada, el radio de 10.0 funciona bien para mí, si 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: el 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, simplemente llame maskByRoundingCornera cualquiera UIView:

view.maskByRoundingCorners([.topLeft, .bottomLeft])
PL
fuente
¿Es esto posible sin dejar de agregar un borde?
Unome
2
Tuve que poner la llamada de función en DispatchQueue.main.async {} porque solo se redondeó una esquina ...
Maksim Kniazev
1
@MaksimKniazev sí, esto debe llamarse desde el hilo principal (UI). Esta regla se aplica a cualquier acción que toque la interfaz de usuario, deben llamarse desde el hilo principal o podrían suceder cosas extrañas.
PL
1
sólo una esquina parece redondearse. Probé la solución @MaksimKniazev tampoco funcionó.
Gustavo_fringe
Tengo el mismo problema que @Gustavo_fringe, donde la esquina superior derecha no está recortada / enmascarada dentro de los límites (redimensionados) de una vista xib, no estoy seguro de cómo solucionarlo todavía.
CyberMew
57

No pude encajar todo esto en un comentario a la respuesta de @ lomanf. Así que lo agrego como respuesta.

Como dijo @lomanf, debe agregar una máscara de capa para evitar que las subcapas se dibujen fuera de los límites de su ruta. Sin embargo, ahora es mucho más fácil de hacer. Siempre que apunte a iOS 3.2 o superior, no necesita crear una imagen con cuarzo y configurarla como máscara. Simplemente puede crear un CAShapeLayercon a UIBezierPathy usarlo como máscara.

Además, cuando use máscaras de capa, asegúrese de que la capa que está enmascarando no sea parte de ninguna jerarquía de capas cuando agregue la máscara. De lo contrario, el comportamiento no está definido. Si su vista ya está en la jerarquía, debe eliminarla de su supervista, enmascararla y luego volver a colocarla donde estaba.

CAShapeLayer *maskLayer = [CAShapeLayer layer];
UIBezierPath *roundedPath = 
  [UIBezierPath bezierPathWithRoundedRect:maskLayer.bounds
                        byRoundingCorners:UIRectCornerTopLeft |
                                          UIRectCornerBottomRight
                              cornerRadii:CGSizeMake(16.f, 16.f)];    
maskLayer.fillColor = [[UIColor whiteColor] CGColor];
maskLayer.backgroundColor = [[UIColor clearColor] CGColor];
maskLayer.path = [roundedPath CGPath];

//Don't add masks to layers already in the hierarchy!
UIView *superview = [self.view superview];
[self.view removeFromSuperview];
self.view.layer.mask = maskLayer;
[superview addSubview:self.view];

Debido a la forma en que funciona el renderizado de Core Animation, el enmascaramiento es una operación relativamente lenta. Cada máscara requiere una pasada de renderización adicional. Por lo tanto, use máscaras con moderación.

Una de las mejores partes de este enfoque es que ya no es necesario crear una función personalizada UIViewy anular drawRect:. Esto debería hacer que su código sea más simple y quizás incluso más rápido.

Nathan Eror
fuente
Parece prometedor, pero la vista no aparece. ¿Alguna idea de por qué?
Jumhyn
10
Está utilizando maskLayer.bounds para dimensionar UIBezierPath pero el valor de los límites es CGRectZero. Debe agregar una segunda línea de código (inmediatamente después de la inicialización de CAShapeLayer) como maskLayer.frame = self.view.bounds;
lomanf
1
Sí tienes razón. Extraje ese código de otro ejemplo donde la capa de forma ya existía. Lo siento por eso.
Nathan Eror
¡Funciona perfecto! Agregar maskLayer.frame = self.view.bounds, como se indicó anteriormente, hace que funcione. De lo contrario, las vistas no se muestran.
Daniel Ribeiro
+1 Esto funciona bastante bien. De hecho, creo que prefiero este método a la solución n. ° 2 de lomanf. Este método le permite agregar arcos a las esquinas opuestas (por ejemplo: Arriba a la derecha + Abajo a la izquierda), y ciertamente es más corto que la primera solución de lomanf. ¡Gran código Nathan!
FreeAsInBeer
30

He tomado el ejemplo de Nathan y he creado una categoría UIViewpara permitir que uno se adhiera a los principios DRY. Sin más preámbulos:

UIView + Roundify.h

#import <UIKit/UIKit.h>

@interface UIView (Roundify)

-(void)addRoundedCorners:(UIRectCorner)corners withRadii:(CGSize)radii;
-(CALayer*)maskForRoundedCorners:(UIRectCorner)corners withRadii:(CGSize)radii;

@end

UIView + Roundify.m

#import "UIView+Roundify.h"

@implementation UIView (Roundify)

-(void)addRoundedCorners:(UIRectCorner)corners withRadii:(CGSize)radii {
    CALayer *tMaskLayer = [self maskForRoundedCorners:corners withRadii:radii];
    self.layer.mask = tMaskLayer;
}

-(CALayer*)maskForRoundedCorners:(UIRectCorner)corners withRadii:(CGSize)radii {
    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.frame = self.bounds;

    UIBezierPath *roundedPath = [UIBezierPath bezierPathWithRoundedRect:
        maskLayer.bounds byRoundingCorners:corners cornerRadii:radii];
    maskLayer.fillColor = [[UIColor whiteColor] CGColor];
    maskLayer.backgroundColor = [[UIColor clearColor] CGColor];
    maskLayer.path = [roundedPath CGPath];

    return maskLayer;
}

@end

Llamar:

[myView addRoundedCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight
                withRadii:CGSizeMake(20.0f, 20.0f)];
FreeAsInBeer
fuente
2
No olvide importar <QuartzCore / QuatzCore.h> en el archivo .m y también agregar QuartzCore.framework al proyecto
DEzra
+1 Buen material, sin embargo, una pregunta, ¿cuál es el propósito de eliminar / leer la vista en su supervista?
eladleb
@eladleb: El código básico aquí fue de Nathan, simplemente lo optimicé un poco. De la investigación que he realizado, no puedo encontrar una razón válida para eliminar la vista antes de aplicar la máscara de capa. Por lo tanto, creo que es seguro omitir ese código.
FreeAsInBeer
@FreeAsInBeer - Estoy de acuerdo, luego votaría por eliminarlo, esto en realidad cambia el orden z de la vista y puede crear más problemas ..
eladleb
Resolvió el problema que tenía al agregar esquinas redondeadas a un TableView: agregué un encabezado, esquinas redondeadas y agregué un pie de página con esquinas inferiores redondeadas. Gracias.
Noche fijada el
24

Para expandir un poco la respuesta de PL, reescribí el método como para que no redondeara ciertos objetos como UIButtoncorrectamente

- (void)setMaskTo:(id)sender byRoundingCorners:(UIRectCorner)corners withCornerRadii:(CGSize)radii
{
    // UIButton requires this
    [sender layer].cornerRadius = 0.0;

    UIBezierPath *shapePath = [UIBezierPath bezierPathWithRoundedRect:[sender bounds]
                                                byRoundingCorners:corners
                                                cornerRadii:radii];

    CAShapeLayer *newCornerLayer = [CAShapeLayer layer];
    newCornerLayer.frame = [sender bounds];
    newCornerLayer.path = shapePath.CGPath;
    [sender layer].mask = newCornerLayer;
}

Y llámalo por

[self setMaskTo:self.continueButton byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerBottomRight withCornerRadii:CGSizeMake(3.0, 3.0)];
Josh Valdivieso
fuente
12

Si desea hacerlo en Swift, puede usar una extensión de UIView. Al hacerlo, todas las subclases podrán utilizar el siguiente método:

import QuartzCore

extension UIView {
    func roundCorner(corners: UIRectCorner, radius: CGFloat) {
        let maskPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let maskLayer = CAShapeLayer()
        maskLayer.frame = bounds
        maskLayer.path = maskPath.CGPath
        layer.mask = maskLayer
    }
}    

Uso de ejemplo:

self.anImageView.roundCorner(.topRight, radius: 10)
Kevin Delord
fuente
3

Ampliando la respuesta aceptada, agreguemos compatibilidad con versiones anteriores. Antes de iOS 11, view.layer.maskedCorners no está disponible. Entonces podemos hacer así

if #available(iOS 11.0, *) {
    myView.layer.maskedCorners = [.layerMinXMinYCorner,.layerMaxXMinYCorner]
} else {
    myView.maskByRoundingCorners([.topLeft, .topRight])
}

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

Hemos escrito maskByRoundingCorners como una extensión de UIView para que mejore la reutilización del código.

Créditos a @SachinVsSachin y @PL :) He combinado sus códigos para hacerlo mejor.

Rizwan Ahmed
fuente
2
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(5, 5, self.bounds.size.width-10, self.bounds.size.height-10)
                                               byRoundingCorners:UIRectCornerAllCorners
                                                     cornerRadii:CGSizeMake(12.0, 12.0)];

cambie "AllCorners" según su necesidad.

Umang
fuente
Entonces, ¿tiene que hacer esto en UIView o se puede hacer en UIViewController? ¿Qué haces con el UIBezierPath una vez que lo has hecho? Gracias.
StoneBreaker
2

Todas las soluciones aportadas consiguen el objetivo. Pero, UIConstraintsa veces puede hacer estallar esto.

Por ejemplo, es necesario redondear las esquinas inferiores. Si la restricción de espaciado de altura o inferior se establece en la UIView que debe redondearse, los fragmentos de código que redondean las esquinas deben moverse al viewDidLayoutSubviewsmétodo.

Destacando:

UIBezierPath *maskPath = [UIBezierPath
    bezierPathWithRoundedRect:roundedView.bounds byRoundingCorners:
    (UIRectCornerTopRight | UIRectCornerBottomRight) cornerRadii:CGSizeMake(16.0, 16.0)];

El fragmento de código anterior solo redondeará la esquina superior derecha si este código se establece en viewDidLoad. Porque roundedView.boundsva a cambiar después de que las restricciones actualicen UIView.

hasan
fuente
1

Crea una máscara y colócala en la capa de la vista.

Steve Riggins
fuente
¿Como podría hacerlo? Soy un poco inestable en lo que respecta a la gestión de vistas de nivel inferior.
Jumhyn
1
stackoverflow.com/questions/2264083/ ... podría ayudarlo
Steve Riggins
1
¡Me alegra ver que mi respuesta sigue ayudando a la gente!
nevan king
1

Comenzando con su código, puede ir con algo como el fragmento de abajo.

No estoy seguro de si este es el tipo de resultado que busca. Vale la pena señalar, también, que si / cuando el sistema llama a drawRect: nuevamente, pidiendo que solo se vuelva a dibujar una parte del rect, esto se comportará de manera muy extraña. El enfoque de Nevan , mencionado anteriormente, podría ser una mejor manera de hacerlo.

 // make sure the view's background is set to [UIColor clearColor]
- (void)drawRect:(CGRect)rect
{
    CGFloat radius = 10.0;
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(context, rect.size.width/2, rect.size.height/2);
    CGContextRotateCTM(context, M_PI); // rotate so image appears right way up
    CGContextTranslateCTM(context, -rect.size.width/2, -rect.size.height/2);

    CGContextBeginPath(context);

    CGContextMoveToPoint(context, rect.origin.x, rect.origin.y);
    CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, radius, M_PI, M_PI / 2, 1);
    CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1);
    CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y);
    CGContextClip(context); 

    // now do your drawing, e.g. draw an image
    CGImageRef anImage = [[UIImage imageNamed:@"image.jpg"] CGImage];
    CGContextDrawImage(context, rect, anImage);    
}
Oblicuamente
fuente
Trabajé en una vista con esquinas redondeadas, pero no puedo hacer que recorte ninguna de sus subvistas. Si coloco una vista con esquinas cuadradas en el borde de mi vista, todavía cubre las esquinas redondeadas de su supervista. ¿Alguna idea de por qué está pasando esto?
Jumhyn
Porque el recorte -drawRect:solo afecta la vista que está dibujando. Sus subvistas se dibujan de forma independiente después de que se completa el dibujo.
Jonathan Grynspan
1

Una forma un poco hacky, pero relativamente simple (sin subclases, enmascaramiento, etc.) es tener dos UIViews. Ambos con clipToBounds = YES. Establezca esquinas redondeadas en la vista secundaria, luego colóquela dentro de la vista principal para que las esquinas que desea rectas queden recortadas.

UIView* parent = [[UIView alloc] initWithFrame:CGRectMake(10,10,100,100)];
parent.clipsToBounds = YES;

UIView* child = [[UIView alloc] new];
child.clipsToBounds = YES;
child.layer.cornerRadius = 3.0f;
child.backgroundColor = [UIColor redColor];
child.frame = CGRectOffset(parent.bounds, +4, -4);


[parent addSubView:child];

No es compatible con el caso en el que desea redondear dos esquinas diagonalmente opuestas.

William Denniss
fuente
1

La ruta de Bezier es la respuesta, si necesita un código adicional, este funcionó para mí: https://stackoverflow.com/a/13163693/936957

UIBezierPath *maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:_backgroundImageView.bounds 
                                 byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight) 
                                       cornerRadii:CGSizeMake(3.0, 3.0)];

CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.bounds;
maskLayer.path = maskPath.CGPath;
_backgroundImageView.layer.mask = maskLayer;
[maskLayer release];
Yunus Nedim Mehel
fuente
1

Solución UIBezierPath.

- (void) drawRect:(CGRect)rect {

    [super drawRect:rect];

    //Create shape which we will draw. 
    CGRect rectangle = CGRectMake(2, 
                                  2, 
                                  rect.size.width - 4,
                                  rect.size.height - 4);

    //Create BezierPath with round corners
    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:rectangle 
                                                   byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight 
                                                         cornerRadii:CGSizeMake(10.0, 10.0)];

    //Set path width
    [maskPath setLineWidth:2];

    //Set color
    [[UIColor redColor] setStroke];

    //Draw BezierPath to see it
    [maskPath stroke];
}
Alexey Bondarchuk
fuente
0

Esto solo puede funcionar si algunas cosas están configuradas correctamente:

  1. clipsToBounds debe establecerse en YES
  2. opaco tiene que ser NO
  3. backgroundColor debe ser "clearColor" (no estoy completamente seguro de esto)
  4. contentMode tiene que ser "UIContentModeRedraw" ya que no se llama a drawRect con frecuencia si no lo es
  5. [super drawRect: rect] tiene que ser llamado después de CGContextClip
  6. Es posible que su vista no contenga subvistas arbitrarias (no estoy seguro de esto)
  7. Asegúrese de configurar "needDisplay:" al menos una vez para activar su rectificación
Dunkelstern
fuente
0

Me doy cuenta de que está tratando de redondear las dos esquinas superiores de un UITableView, pero por alguna razón, descubrí que la mejor solución es usar:

self.tableView.layer.cornerRadius = 10;

Programáticamente debería redondear las cuatro esquinas, pero por alguna razón solo redondea las dos primeras. ** Consulte la captura de pantalla a continuación para ver el efecto del código que escribí arriba.

¡Espero que esto ayude!

ingrese la descripción de la imagen aquí

Adam Cooper
fuente
1
Si no está redondeando todas las esquinas del, UITableViewentonces debe haber un código en otro lugar que haga que UITableViewno tenga esquinas redondeadas en la parte inferior, o tal vez incluso un UIViewo UILabelque cubra la parte inferior del UITableView.
Josh Valdivieso
-1

Probablemente tengas que recortar hasta los límites. Agrega la línea

self.clipsToBounds = YES

en algún lugar del código para establecer esa propiedad.

Ned
fuente