2013-08-27 13 views
28

Negli documentation stati di Apple che è necessario prendere in considerazione il fattore di scala di un livello quando:Quando è necessario impostare la proprietà contentsScale di un CALayer?

  • crea ulteriori strati Core Animation con diversi fattori di scala e li compositi nel proprio contenuto
  • Imposta il contenuti di proprietà di uno strato core Animation direttamente

L'ultima affermazione non è del tutto chiaro per me. Dicono anche:

Le applicazioni che utilizzano strati Core Animation direttamente per fornire contenuti può essere necessario regolare il loro codice di disegno per tenere conto di scala fattori. Normalmente, quando disegni drawRect: method, o nel drawLayer: inContext: metodo del delegato del layer, il sistema aggiusta automaticamente il contesto grafico all'account per i fattori di scala .

Normalmente o sempre? e questo è valido solo per il livello di supporto ospitato dalla vista o per ogni livello che aggiungo come sottolivello al livello di supporto? perché dicono anche:

Se l'applicazione crea strati senza una visualizzazione associata, fattore di scala ogni nuovo oggetto strato è impostato su 1,0 inizialmente. Se non si modifica il fattore di scala e se successivamente si disegna il livello su uno schermo ad alta risoluzione , il contenuto del livello viene ridimensionato automaticamente per compensare la differenza di fattori di scala. Se non vuoi che il contenuto sia ridimensionato, puoi modificare il fattore di scala del livello su 2.0, ma se lo fai senza fornire contenuti ad alta risoluzione, il tuo contenuto esistente potrebbe apparire più piccolo di quanto ti aspettavi. Per risolvere il problema , è necessario fornire contenuti a più alta risoluzione per il livello .


Sto avendo difficoltà immaginando uno strato senza vista, posso immaginare una gerarchia di livelli, ma non appena voglio visualizzare li dovrei aggiungerlo come subhierachy di strato di supporto della vista, o esistono altri modi per usarli (come la creazione e il rendering in un contesto)?

Nucleo motore di compositing di animazione guarda la proprietà contentsScale di ogni strato per determinare se il contenuto di quello strato devono essere scalati durante compositing. Se l'applicazione crea livelli senza una vista associata, il fattore della scala di ogni nuovo oggetto livello è inizialmente impostato su 1.0. Se non si modifica il fattore di scala e se si disegna successivamente il livello su uno schermo ad alta risoluzione , il contenuto del livello viene ridimensionato automaticamente per compensare per la differenza di fattori di scala. Se non si desidera ridimensionare il contenuto , è possibile modificare il fattore di scala del livello su 2.0, ma se lo fai senza fornire contenuti ad alta risoluzione, il tuo contenuto esistente potrebbe apparire più piccolo di quanto ti aspettassi. Per risolvere il problema , è necessario fornire contenuti a più alta risoluzione per il livello.

Che cosa significa in realtà? Quando faccio qualcosa del genere, layer.contents = (id)image.CGImage ho bisogno di impostare il contenutoScale.
Devo anche impostarlo quando il mio livello disegna il suo contenuto chiamando il metodo delegato drawLayer:inContext: e il livello non è il livello di supporto di una vista?

+0

Nel caso ** iOS **, è completamente spiegato qui: https://stackoverflow.com/a/ 47760444/294884 e qui: https://stackoverflow.com/a/47778332/294884 Spero che aiuti qualcuno. – Fattie

risposta

14

Re: contenuto del livello via -drawRect: o -drawLayer: InContext:

normallly o sempre? e questo è valido solo per il livello di supporto ospitato dalla vista o per ogni livello che aggiungo come sottolivello al livello di supporto?

Sempre. Quando vengono chiamati questi metodi, al contesto corrente verrà applicato il fattore di ridimensionamento. Ad esempio, se il tuo layer è 10pt x 10pt, ha un limite di {0,0,10,10}, indipendentemente da contentScale. Se contentScale = 2 (ad esempio, sei su retina), questo è in realtà 20x20 pixel. CALayer avrà già impostato un backing store 20x20px e applicato un fattore di scala CGContextScaleCTM (context, 2, 2).

Ciò consente di eseguire il disegno nello spazio concettuale 10x10 in entrambi i casi, ma il backing store viene raddoppiato se i pixel vengono raddoppiati.

Sto avendo difficoltà immaginando uno strato senza vista, posso immaginare una gerarchia di strati ma appena voglio visualizzare li dovrei aggiungere come subhierachy di strato di supporto della vista , o esistono altri modi per usarli (come la creazione e solo il rendering di in un contesto)?

È possibile crearli, aggiungerli come sottolivelli, e sia inserito il suo delegato a un oggetto in cui si implementano -drawLayer: InContext :, oppure si può impostare direttamente il contenuto del livello. Su iOS, UIView è un wrapper piuttosto superficiale attorno a un CALayer, quindi in genere ha senso creare sottoview invece di creare direttamente i sottolivelli, motivo per cui non si è così familiari con questo utilizzo. Su OS X, NSView con layer layer è un wrapper grande e complicato su un CALayer, quindi ha molto più senso creare intere gerarchie di layer all'interno di una singola vista.

Che cosa significa in realtà? Quando faccio qualcosa del genere layer.contents = (id) image.CGImage Ho bisogno di impostare il contenutoScale.

Sì. Ma ciò che questo passaggio della documentazione ti sta dicendo è che se vuoi non sembrare brutto, un livello 10pt x 10pt con contenuto Scala 2, ha bisogno di contenuti che sono un'immagine 20px x 20px. Cioè È necessario prestare attenzione al contenuto Scala del livello quando si impostano direttamente i contenuti del livello se si desidera evitare di ridimensionare gli artefatti.

fare Ho anche bisogno di impostare quando il mio strato trae il suo contenuto chiamando il metodo delegato drawLayer : InContext: e lo strato non è strato di supporto di una visione?

Sì. Se stai creando dei layer da solo (non creati tramite un UIView), devi impostare la loro scala manualmente. Di solito questo è solo layer.contentsScale = [[UIScreen mainScreen] scale]. (Ancora una volta, su OS X questo è un po 'più complicato dal momento che gli schermi possono entrare e uscire durante l'esecuzione.)

+0

Grazie per la risposta dettagliata! Se A e B sono entrambi figli del layer Z, anche il layer Z deve impostare contentScale o contentScale del parent non importa? – Crashalot

5

Su OS X che, fondamentalmente,

  1. afferrare -backingScaleFactor
  2. set di finestra ogni (!) Di -contentsScale strato a quello scaleFactor
  3. implementare -layer:shouldInheritContentsScale:fromWindow: in un controllore
  4. set di -delegate al controller ogni strato

So che è per qui su SO per fare semplicemente riferimento a un URL esterno, ma è difficile descriverlo. Ecco alcuni codice che funziona correttamente per me per quanto riguarda i fattori di scala:

https://github.com/JanX2/ScrollingAboutWindow

Speranza che aiuta.

+0

Una soluzione alternativa valida sarebbe quella di impostare il livello (oi livelli) 'contentsScale' da' viewDidChangeBackingProperties' (o 'windowDid ...')? –

+0

Nessuna idea. AFAIK, questo è il modo in cui Apple ti dice di usare. – JanX2

5

Mentre un livello è quasi sempre utilizzato all'interno di una vista, il livello potrebbe essere stato creato ad-hoc e aggiunto come sottostrato del livello della vista o assegnato come maschera di un altro livello. In entrambi i casi, è necessario impostare la proprietà contentsScale. Per esempio:

UIView *myMaskedView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; 
CALayer *myMaskLayer = [CALayer new]; 
myMaskLayer.frame = myMaskedView.bounds; 
UIImage *maskImage = [UIImage imageNamed:@"some_image"]; 
myMaskLayer.contents = (id)maskImage.CGImage; 
myMaskLayer.contentsScale = maskImage.scale; 
myMaskedView.layer.mask = myMaskLayer; 

Si consiglia inoltre di costruire una gerarchia di livelli per l'esecuzione di animazioni, senza l'utilizzo di ogni strato per eseguire una vista:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; 

CALayer *sublayerA = [CALayer new]; 
sublayerA.contentsScale = myView.layer.contentsScale; 
[myView.layer addSublayer:sublayerA]; 

CALayer *sublayerB = [CALayer new]; 
sublayerB.contentsScale = myView.layer.contentsScale; 
[myView.layer addSublayer:sublayerB]; 

// Continue adding layers 

Ciò è particolarmente importante per i dispositivi Retina, che hanno una scala nativa dello schermo di 2.0; un livello con la scala predefinita di 1.0 mostrerebbe una notevole pixelizzazione.

+0

Aha! Il fatto che ciò non si applichi ai livelli creati da uno stesso spiega perché il livello ospitato sul mio Mac non ha impostato correttamente "contentScale". Considero che se la mia vista fosse a strati invece che a livello di hosting, allora sarebbe stata impostata per me dalla vista (al livello NSView) quando ha creato il suo livello. –

+0

Penso che questa risposta e questo commento siano arrivati ​​alla domanda che avevo mentre stavo leggendo questa domanda: quando crei un livello e poi lo aggiungi a una gerarchia di livelli che è collegata a una vista, l'atto di aggiungere il livello non viene impostato da solo la proprietà contentScale a quella dello schermo, corretta? – s73v3r

+1

Ciò è corretto. L'aggiunta di un livello alla gerarchia della vista non imposta il suo 'contentsScale'. – Austin

Problemi correlati