2013-10-24 9 views
16

Sto disegnando foto avatar, applicando solo cornerRadius a un livello UIImageView e aggiungendo un bordo tramite borderWith e borderColor. In questo modo:iOS: rettangolo arrotondato con bordo bleed colore

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

che funziona grande, ad eccezione di questo piccolo, ma evidente emorragia di contenuti al di fuori del confine, in questo modo:

Content bleeding outside the mask and border

C'è un modo per appena fin frontiera da pochi punti 1/10, o inserire il contenuto più del confine?


Soluzione

Grazie a FelixLam, mi si avvicinò con una bella soluzione e lasceranno qui per l'aldilà:

@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 
+1

Si può cercare di aggiungere un trasparente bordo di 1 pixel per il file di immagine, quindi l'immagine sarà di 2 pixel più larga e più alta, questo dovrebbe aiutare con la fusione – dariaa

risposta

13

si potrebbe tentare di utilizzare un CAShapelayer con un percorso circolare come maschera per il livello invece di utilizzare il raggio dell'angolo.

In alternativa, è possibile posizionare la vista dell'immagine in un contenitore con il bordo più grande di uno/due pixel.

+1

Grazie per le idee! Sono andato con la seconda opzione, sembra fantastico :) – manmal

-1

impostazione Prova:

[self setClipToBounds:YES] 
+0

Non è lo stesso di 'self.layer.masksToBounds = YES;' – FelixLam

+0

Sì. Ho cercato solo di essere sicuro, nessun effetto. – manmal

1

Come detto nei commenti, è possibile aggiungere un bordo trasparente per l'immagine in modo che sarà ok. Ecco un pezzo di codice per farlo (una categoria per 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; 
} 
+1

Questa è una soluzione subottimale. Dovrai sempre rigenerare l'immagine se viene recuperata da una cache o aggiornata. Disegnare un bordo attorno a un'immagine è IMO un problema di rendering, non un problema di contenuto. – manmal

+0

Certo, non è pulito. Ma funziona ancora in caso di necessità ^^ – AncAinu

+0

Quando ci sono 9 modi per raggiungere un obiettivo, non scegliere quello sbagliato. O il tuo codice base marcirà molto presto. – manmal

-1

Ho avuto lo stesso problema e volevamo una soluzione che avrebbe funzionato bene con uno storyboard. Quello che ho fatto è stato posizionare la mia immagine all'interno di una vista e quindi impostare sia su una classe personalizzata che controlla il comportamento. Ora posso controllare completamente il design da uno storyboard.

Ho inserito il codice su GitHub.

https://github.com/brennanMKE/CircleButton

ciò che fa è ignorare la funzione drawRect in UIView sia per un'UIButton e UIView regolare in modo che possa lavorare con molti punti di vista. Una vista wrapper viene anche utilizzata per controllare il colore e la larghezza del bordo. Mi limito ad accertarmi che ci sia un certo margine tra la vista avvolta e la superview e utilizzi la differenza come larghezza del bordo. Il colore di sfondo della superview diventa il colore del bordo. Ora posso apportare rapidamente queste modifiche in molte scene in uno storyboard senza codifica personalizzata di ogni istanza.

- (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; 
    } 
} 
+0

Grazie. La mia soluzione non funziona negli storyboard (non che mi importi davvero)? Imposta anche '' 'shouldRasterize''' a' '' YES''' su entrambi i livelli o le prestazioni peggioreranno considerevolmente. Il mascheramento sembra essere molto costoso. – manmal

+1

Si tratta di un disegno rottame abusivo, la maggior parte di questa roba dovrebbe accadere solo quando il frame cambia. –

0

La soluzione dell'OP è inutilmente complicata. Una soluzione più semplice e pulita. Crea un UIView, aggancia i bordi, la maschera, il bordo e il raggio dell'angolo come sopra e poi aggiungi una vista UIIam come sottoview di tale UIView. L'UIIamgeview verrà ritagliato dalla vista genitore e non avrai il problema di sanguinamento.

0

Il mio UIButton necessitava di un raggio dell'angolo arrotondato che creava bordi frastagliati. Impostando borderStyle su .roundedRect risolto.

button.borderStyle = .roundedRect 
button.layer.cornerRadius = 4 
button.layer.borderWidth = 1 
button.layer.borderColor = .red.cgColor 
Problemi correlati