iOS: rectángulo networkingondeado con color de sangrado en el borde

Estoy dibujando imágenes networkingondas de avatar, simplemente aplicando cornerRadius a la cornerRadius de un UIImageView , y también agregando un borde a través de borderWith y borderColor . Al igual que:

 self.layer.masksToBounds = YES; self.layer.cornerRadius = imageDimension / 2.f; self.layer.borderWidth = 1.f; self.layer.borderColor = borderColor.CGColor; 

Eso funciona muy bien, a exception de esta pequeña, pero notoria sangría de contenido fuera del límite, así:

Contenido sangrado fuera de la máscara y el borde

¿Hay alguna forma de comenzar el borde por unos 1/10 puntos, o de insert el contenido más que el borde?


Solución

Gracias a FelixLam, se me ocurrió una buena solución y la dejaré aquí para el más allá:

 @interface MMRoundImageViewWithBorder : UIView - (id)initWithImage:(UIImage *)image borderWidth:(CGFloat)borderWidth; @property (strong, nonatomic) UIImageView *imageView; @property (assign, nonatomic) CGFloat borderWidth; @property (strong, nonatomic) UIColor *borderColor; @end @implementation MMRoundImageViewWithBorder - (id)initWithImage:(UIImage *)image borderWidth:(CGFloat)borderWidth { if (self = [super init]) { self.borderWidth = borderWidth; self.borderColor = UIColor.whiteColor; self.imageView = [[UIImageView alloc] initWithImage:image]; [self addSubview:self.imageView]; self.imageView.layer.masksToBounds = YES; self.layer.masksToBounds = YES; } return self; } - (void)setBorderColor:(UIColor *)borderColor { _borderColor = borderColor; self.backgroundColor = borderColor; } - (void)layoutSubviews { [super layoutSubviews]; [self refreshDimensions]; } - (void)refreshDimensions { self.layer.cornerRadius = CGRectGetWidth(self.bounds) / 2.f; self.imageView.frame = CGRectInset(self.bounds, _borderWidth, _borderWidth); self.imageView.layer.cornerRadius = CGRectGetWidth(self.imageView.bounds) / 2.f; } - (void)setBorderWidth:(CGFloat)borderWidth { _borderWidth = borderWidth; [self refreshDimensions]; } - (void)setFrame:(CGRect)frame { [super setFrame:frame]; [self refreshDimensions]; } @end 

Podría intentar utilizar un CAShapelayer con una ruta circular como máscara para la Capa en lugar de utilizar el radio de la esquina.

Alternativamente, puede colocar la vista de la image en un contenedor que tiene el borde y es uno o dos píxeles más grande.

Como se dijo en los comentarios, puede agregar un borde transparente a la image para que esté bien. Aquí hay una parte del código para hacerlo (una categoría para UIImageView):

 + (UIImage *)imageWithImage:(UIImage *)image withTransparentBorderOfWidth:(CGFloat)width { CGSize size = image.size; UIGraphicsBeginImageContextWithOptions(CGSizeMake(size.width + width * 2, size.height + width * 2), NO, 0.0); [image drawInRect:CGRectMake(width, width, size.width, size.height)]; image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } 

La solución de OP es innecesariamente complicada. Una solución más fácil y más limpia. Cree una UIView, clip a límites, máscara, borde y radio de esquina como arriba y luego agregue una UIIamgeview como una subvista de esa UIView. El UIIamgeview será recortado por la vista principal y no tendrá el problema de sangrado.

Mi UIButton necesitaba un radio de esquina networkingondeado que daba como resultado bordes irregulares. Establecer borderStyle a .roundedRect solucionó.

 button.borderStyle = .roundedRect button.layer.cornerRadius = 4 button.layer.borderWidth = 1 button.layer.borderColor = .networking.cgColor 

Prueba configuration:

 [self setClipToBounds:YES] 

Tuve el mismo problema y quería una solución que funcione bien con un Storyboard. Lo que hice fue colocar mi image dentro de una vista y luego establecerla en una class personalizada que controla el comportamiento. Ahora puedo controlar totalmente el layout de un Storyboard.

He colocado el código en GitHub.

https://github.com/brennanMKE/CircleButton

Lo que hace es anular la function drawRect en UIView para un UIButton y una UIView normal para que pueda funcionar con muchas vistas. Una vista de contenedor también se usa para controlar el color y el ancho del borde. Simplemente me aseguro de que haya algún margen entre la vista envuelta y la vista de supervisión y use la diferencia como el ancho del borde. El color de background de la supervisión se convierte en el color del borde. Ahora puedo hacer estos cambios rápidamente en muchas escenas de Storyboard sin encoding personalizada en cada instancia.

 - (void)drawRect:(CGRect)rect { // round view and superview with a border using the background color of the superview self.layer.cornerRadius = CGRectGetWidth(self.frame) / 2; self.layer.masksToBounds = YES; if ([self.superview isKindOfClass:[SSTCircleWrapperView class]]) { self.superview.layer.cornerRadius = CGRectGetWidth(self.superview.frame) / 2; self.superview.layer.masksToBounds = YES; self.superview.layer.borderColor = self.superview.backgroundColor.CGColor; self.superview.layer.borderWidth = (CGRectGetWidth(self.superview.frame) - CGRectGetWidth(self.frame)) / 2; } }