2014-09-09 11 views
16

Ho un UIView personalizzato che disegna qualcosa in una sovrascrittaiOS disegno in CALayers drawInContext è o sgranata o sfocata sulla retina

- (void)drawRect:(CGRect)rect 

questo funziona bene e dà risultati nitide su schermi retina.

Tuttavia, ora desidero rendere animabili le proprietà su cui è basato il disegno. Creazione di proprietà animatable sembra essere possibile solo sulla CALayer, così invece di fare il disegno in UIView, creo un CALayer sottoclasse personalizzata e fare il disegno all'interno

- (void) drawInContext:(CGContextRef)ctx 

Io uso più o meno lo stesso codice esatto disegno in questo funzione come ho usato nella funzione drawRect della UIView personalizzata.

Il risultato sembra lo stesso - tuttavia, non è la risoluzione della retina, ma pixel nell'immagine (grandi pixel quadrati)

se metto

self.contentsScale = [UIScreen mainScreen].scale; 

Per l'inizio della mia implementazione drawInContext, allora invece di un pixel risultato, ottengo un risultato sfocato (come se il rendering fosse ancora eseguito in risoluzione non retina e quindi upscalizzato alla risoluzione della retina).

qual è il modo corretto per rendere nitidi i percorsi della retina in CALYers drawInContext?

Ecco alcuni screenshot (la linea blu è parte del disegno personalizzato in discussione la parte gialla è solo un'immagine.)

Drawn all'interno drawRect personalizzato di UIView:

enter image description here

Drawn all'interno drawInContext dell'abitudine CALayer:

enter image description here

Drawin all'interno drawInContext personalizzato di CALayer, con l'impostazione self.contentScale prima:

enter image description here

Per completezza, ecco (una versione ridotta del) codice di disegno:

//if drawing inside custom UIView sublcass: 
- (void)drawRect:(CGRect)rect 
{ 
    CGContextRef currenctContext = UIGraphicsGetCurrentContext(); 
    [[UIColor blackColor] set]; 

    CGContextSetLineWidth(currenctContext, _lineWidth); 
    CGContextSetLineJoin(currenctContext,kCGLineJoinRound); 

    CGContextMoveToPoint(currenctContext,x1, y1); 
    CGContextAddLineToPoint(currenctContext,x2, y2); 
    CGContextStrokePath(currenctContext); 
} 

//if drawing inside custom CALayer subclass: 
- (void) drawInContext:(CGContextRef)ctx { 
{ 
    //self.contentsScale = [UIScreen mainScreen].scale; 

    CGContextRef currenctContext = ctx; 
    CGContextSetStrokeColorWithColor(currenctContext, [UIColor blackColor].CGColor); 

    CGContextSetLineWidth(currenctContext, _lineWidth); 
    CGContextSetLineJoin(currenctContext,kCGLineJoinRound); 

    CGContextMoveToPoint(currenctContext,x1, y1); 
    CGContextAddLineToPoint(currenctContext,x2, y2); 
    CGContextStrokePath(currenctContext); 
} 

per ribadire ciò che voglio raggiungere : Voglio ottenere lo stesso rendering della retina nitido come nell'approccio UIView, ma durante il rendering in CALayer

+0

nella retina display, è necessario moltiplicare l'altezza e la larghezza per 2. – Bejibun

+0

no, la dimensione e la posizione sullo schermo è corretta – user1282931

+0

intendo lo schermo devi solo creare moltiplicato per 2, perché il display retina richiede una doppia risoluzione. – Bejibun

risposta

8

Stai utilizzando shouldRasterize = YES nel livello? Prova a disegnare nella sottoclasse CALayer, ma imposta rasterizationScale sulla scala dello schermo.

+0

ha dovuto impostare rasterizationScale su scala schermo * 4.0 per ottenere linee affumicate ... –

+0

@AndresCanella su quale dispositivo hai utilizzato 4.0 per rasterizationScale? – Crashalot

+0

@Crashalot I ha finito per utilizzare la scala dello schermo * 2.0 su i6. Stavo perdendo croccantezza su 4.0. –

3

Il problema è più probabile che sia contentScale qui; tenere presente che se si assegna questo a una vista personalizzata sovrascrivendo la sua funzione layerClass, la scala del contenuto del livello potrebbe essere ripristinata. Potrebbero esserci altri casi in cui ciò accade anche. Per sicurezza, imposta la scala del contenuto solo dopo che il livello è stato aggiunto a una vista.

Provare ad assegnare la scala della schermata principale al livello personalizzato durante il metodo init della vista personalizzata.In Swift 3 che assomiglia a questo:

layer.contentsScale = UIScreen.mainScreen().scale 

O, in Swift 4:

layer.contentsScale = UIScreen.main.scale 
+0

Bella cattura! Grazie uomo –

3

Dopo aver aggiunto al suo livello superlayer. set shouldRasterize su YES, impostare contentsScale e resterizatioinScale per dimensioni dello schermo:

[self.progressView.layer addSublayer:self.progressLayer]; 
self.progressLayer.shouldRasterize = YES; 
self.progressLayer.contentsScale = kScreenScale; 
self.progressLayer.rasterizationScale = kScreenScale; 

CABasicAnimation *animate = [CABasicAnimation animationWithKeyPath:@"progress"];// progress is a customized property of progressLayer 
animate.duration = 1.5; 
animate.beginTime = 0; 
animate.fromValue = @0; 
animate.toValue = @1; 
animate.fillMode = kCAFillModeForwards; 
animate.removedOnCompletion = NO; 
animate.repeatCount = HUGE_VALF; 
[self.progressLayer addAnimation:animate forKey:@"progressAnimation"]; 
Problemi correlati