2013-12-10 17 views
11

sto disegnando un grafico a torta con un CAShapeLayer per ogni fetta della torta. Anche quando l'angolo finale di una fetta di torta è uguale all'angolo iniziale della porzione adiacente, l'antialiasing si traduce nel colore di fondo sottostante che appare tra ogni fetta di torta se il bordo tra le fette è ad angolo.CAShapeLayer Adiacente Antialiasing Problema

http://i.stack.imgur.com/Qdu8d.png

vorrei eliminare il piccolo spazio tra le fette pur utilizzando l'antialiasing in modo che il carrello torta risultante è ancora liscia. Concettualmente, sembra che esistesse un modo per applicare l'antialias a tutto il CALayer e che i sottolivelli della fetta di torta dopo che tutte le fette di torta fossero state disegnate, sarebbe stato il trucco ... Le fette di torta sarebbero state antialiasite l'una nell'altra invece che nel sfondo.

Ho giocato con tutte le proprietà di CALayer che riesco a pensare e sto avendo difficoltà a trovare maggiori informazioni al riguardo. Qualche idea?

AGGIORNAMENTO: Vedere la risposta seguente.

risposta

5

UPDATE: risposta di Rob è piuttosto buona, ma forse i risultati in altre questioni di antialiasing. Ho finito per riempire gli spazi disegnando linee radiali larghe di 1pt lungo l'angolo finale di ogni fetta di torta, ogni linea essendo dello stesso colore della fetta adiacente. Queste linee sono disegnate con un indice z più basso rispetto alle fette di torta, quindi sono sottostanti. Ecco il loro aspetto senza le fette di torta disegnate sulla parte superiore:

The filler lines with no slices drawn.

Ed ecco il prodotto finale:

Final result with lines underneath and slices on top.

8

probabilmente non siete intenzione di essere in grado di effettuare i bordi fetta di torta si incontrano esattamente senza crepe. La soluzione più semplice è non provare.

Invece di fare le vostre fette di torta si incontrano ai bordi, li rendono sovrappongono. Disegnare la prima fetta come un disco pieno:

first slice

quindi disegnare la seconda fetta come un disco completo, fatta eccezione per la corretta area della prima fetta:

second slice

quindi disegnare il terza sezione come un disco pieno, ad eccezione della zona adeguata dei primi due fette:

third slice

E così via:

fourth slicefifth slice

Ecco il mio codice:

#import "PieView.h" 

@implementation PieView { 
    NSMutableArray *slices; 
} 

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
     // Initialization code 
    } 
    return self; 
} 

- (void)layoutSubviews { 
    [super layoutSubviews]; 
    [self layoutSliceLayers]; 
} 

- (void)layoutSliceLayers { 
    if (slices == nil) { 
     [self createSlices]; 
    } 
    [slices enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 
     [self layoutSliceLayer:obj index:idx]; 
    }]; 
} 

static const int kSliceCount = 5; 

- (void)createSlices { 
    slices = [NSMutableArray arrayWithCapacity:kSliceCount]; 
    for (int i = 0; i < kSliceCount; ++i) { 
     [slices addObject:[self newSliceLayerForIndex:i]]; 
    } 
} 

- (CAShapeLayer *)newSliceLayerForIndex:(int)i { 
    CAShapeLayer *layer = [CAShapeLayer layer]; 
    layer.fillColor = [UIColor colorWithWhite:(CGFloat)i/kSliceCount alpha:1].CGColor; 
    [self.layer addSublayer:layer]; 
    return layer; 
} 

- (void)layoutSliceLayer:(CAShapeLayer *)layer index:(int)index { 
    layer.position = [self center]; 
    layer.path = [self pathForSliceIndex:index].CGPath; 
} 

- (CGPoint)center { 
    CGRect bounds = self.bounds; 
    return CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); 
} 

- (UIBezierPath *)pathForSliceIndex:(int)i { 
    CGFloat radius = [self radius]; 
    CGFloat fudgeRadians = 5/radius; 
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointZero 
     radius:radius startAngle:2 * M_PI * i/kSliceCount 
     endAngle:2 * M_PI clockwise:YES]; 
    [path addLineToPoint:CGPointZero]; 
    [path closePath]; 
    return path; 
} 

- (CGFloat)radius { 
    CGSize size = self.bounds.size; 
    return 0.9 * MIN(size.width, size.height)/2; 
} 

@end 
+0

Grazie mille per la risposta, Rob. Ho provato questa soluzione a un certo punto e vedevo artefatti di antialiasing dagli strati più scuri e sottostanti che venivano sottoposti a antialiasing in background. Appare come un sottile bordo scuro attorno al grafico a torta che era particolarmente evidente sul bordo esterno delle fette di colore più chiaro. La soluzione di riempimento radiale che ho descritto sembra funzionare bene. – Aaron

+0

@Aaron Quando si esegue l'anti-alias, si ottiene un anello di colore + pixel alfa attorno a una forma con alias efficace di colore solido. Facendo questo per più forme con lo stesso contorno, la tua area interna effettivamente alias apparirà bene ma la tua zona anti-alias avrà colore (n) + alpha colore sovrapposto (n-1) + alpha sovrapposizione ... colore (0) + alfa. Questo spiega l'effetto che stai vedendo. –