2011-11-29 20 views
22

Ho un oggetto UIView che ruota con CALayer 's trasformazione:antialiasing bordi UIView dopo trasformazione utilizzando CALayer di trasformazione

// Create uiview object. 
UIImageView *block = [[UIImageView alloc] initWithFrame....] 

// Apply rotation. 
CATransform3D basicTrans = CATransform3DIdentity; 
basicTrans.m34 = 1.0/-distance; 
blockImage.layer.transform = CATransform3DRotate(basicTrans, rangle, 1.0f, 0.0f, 0.0f); 

Dopo aver ruotato i bordi dell'oggetto non sono antialiasing. Ho bisogno di antialias li. Aiutami, per favore. Come può essere fatto?

risposta

41

Un modo per farlo è posizionando l'immagine all'interno di un'altra vista più grande di 5 pixel. La vista grande dovrebbe avere un bordo rasterizzata trasparente che smussare i bordi del UIImageView:

view.layer.borderWidth = 3; 
view.layer.borderColor = [UIColor clearColor].CGColor; 
view.layer.shouldRasterize = YES; 
view.layer.rasterizationScale = [[UIScreen mainScreen] scale]; 

Quindi, posizionare l'UIImageView all'interno di questa vista primaria e centrarlo (Con 2,5 pixel attorno ogni bordo).

Infine, ruotare la vista padre anziché la vista immagine.

Funziona molto bene - puoi anche incapsulare l'intera cosa in classe che crea la gerarchia.

+9

È possibile aggiungere 'view.layer.rasterizationScale = [[UIScreen mainScreen] scala];' per evitare sfocature sugli schermi Retina. –

+0

Questo commento dovrebbe far parte della risposta. L'impostazione della proprietà 'shouldRasterize' non è sufficiente! –

+0

Hai ragione. Fatto. – tarmes

30

Basta aggiungere questa coppia chiave-valore al tuo Info.plist: UIViewEdgeAntialiasing impostato su YES.

+1

Questo è killer! – orkenstein

+0

fantastico! Qualche idea del successo della performance? – horseshoe7

+0

Viene fornito con la penalità delle prestazioni, evitarlo se puoi. –

3

Ho avuto un problema simile ruotando attorno all'asse z. Setting shouldRasterize = YES ha prevenuto i bordi frastagliati comunque a un costo di prestazioni. Nel mio caso stavo riutilizzando le viste (e i suoi livelli) e mantenendo il dovrebbe shouldRasterize = YES stava rallentando le cose.

La soluzione era quella di disattivare la rasterizzazione subito dopo che non ne avevo più bisogno. Tuttavia, poiché l'animazione gira su un altro thread, non c'era modo di sapere quando l'animazione era completa ... fino a quando ho scoperto un metodo CATransaction estremamente utile. Si tratta di un codice che ho usato e dovrebbe illustrare il suo uso:

// Create a key frame animation 
CAKeyframeAnimation *wiggle = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; 
NSInteger frequency = 5; // Higher value for faster vibration 
NSInteger amplitude = 25; // Higher value for lower amplitude 
// Create the values it will pass through  
NSMutableArray *valuesArray = [[NSMutableArray alloc] init]; 
NSInteger direction = 1; 

[valuesArray addObject:@0.0]; 

for (NSInteger i = frequency; i > 0; i--, direction *= -1) { 
    [valuesArray addObject:@((direction * M_PI_4 * (CGFloat)i/(CGFloat)amplitude))]; 
} 

[valuesArray addObject:@0.0]; 
[wiggle setValues:valuesArray]; 

// Set the duration 
[wiggle setAdditive:YES]; 
[wiggle setValueFunction:[CAValueFunction functionWithName:kCAValueFunctionRotateZ]]; 
[wiggle setDuration:0.6]; 

// Turn on rasterization to prevent jagged edges (anti-aliasing issues) 
viewToRotate.layer.shouldRasterize = YES; 

// ************ Important step ************** 
// Very usefull method. Block returns after ALL animations have completed. 
[CATransaction setCompletionBlock:^{ 
    viewToRotate.layer.shouldRasterize = NO; 
}]; 
// Animate the layer 
[viewToRotate.layer addAnimation:wiggle forKey:@"wiggleAnimation"]; 

funzionato come un fascino per me.

Non ho provato a utilizzare questo con animazioni implicite (ad esempio le animazioni che si verificano a causa della modifica del valore nella proprietà animabile per un livello non associato alla vista), tuttavia mi aspetto che funzioni finché il metodo CATransaction viene chiamato prima la modifica della proprietà, come garanzia che il blocco viene assegnato a CATransaction prima che inizi un'animazione.

20

controllo allowsEdgeAntialiasing proprietà di CALayer.

block.layer.allowsEdgeAntialiasing = YES; // iOS7 and above. 
+1

proprio come sopra (Info.plist) ma controllo più granulare! Eccellente! – horseshoe7

+1

La risposta accettata funziona esattamente come questa, ma questa funziona meglio. Entrambi passano la stessa RAM, ma questa soluzione offre FPS più elevati all'utente. –

+0

La documentazione per questa proprietà dice che il valore è NO se il valore Info.plist è assente.Apparentemente, non puoi semplicemente impostare solo questa proprietà, ma devi usarla insieme al plist. Non ho provato che cosa succede se la proprietà non è impostata, ma a giudicare dalla risposta da AddisDev, il valore predefinito è sì in quel caso. Quindi, se c'è un impatto sulle prestazioni e non è necessario l'antialias, sembra che la cosa da fare sia impostare questo valore su NO. –

Problemi correlati