2013-03-07 17 views
5

Ho l'app basata su GLKit con alcuni oggetti semplici visualizzati.GLKit's -drawRect: non viene chiamato durante la rotazione dello schermo

Tutto funziona correttamente, tranne la rotazione dello schermo, durante il quale GLKView non viene aggiornato (-drawRect: non viene chiamato). Quindi durante la rotazione la matrice di proiezione non viene aggiornata in base alle dimensioni dello schermo che cambiano dinamicamente e l'aspetto dell'oggetto risulta gravemente (allungato).

+0

Stai usando shader o GLKBaseEffect? –

+0

Provato entrambi: 'GLKBaseEffect' e i miei shader - lo stesso risultato. '-drawRect:' verrà chiamato dopo che l'animazione è stata completata, quindi qualsiasi rendering GL (che normalmente viene posizionato lì) verrà sospeso fino a quel momento. – kpower

+1

Ok. Stavo pensando che forse la proprietà projectionMatrix su GLKBaseEffect era buggata. Ci penserò ... –

risposta

1

Questo semplicemente non funziona come funzionano le animazioni UIKit. I sorta-di spiegare come la metà di esso lavora in this answer, ma cercherò di riassumere i bit rilevanti:

  • Tutto è un rettangolo strutturato. (Ci sono alcune eccezioni, come forse CAShapeLayer, ma questo è vero per la maggior parte.)
  • Le proprietà di UIView sono collegate alle proprietà "dell'albero del modello" di CALayer. Cambiano istantaneamente.
  • Le animazioni funzionano animando le proprietà "albero di presentazione" dal valore iniziale al valore corrente del modello.
  • Il valore iniziale dell'animazione è, per impostazione predefinita, il valore del modello precedente. Specificando UIViewAnimationOptionBeginFromCurrentState si utilizza il valore di presentazione corrente.

Ci sono, naturalmente, alcune eccezioni (CAShapeLayer sembra essere più di un rettangolo strutturato, UIScrollView fa scorrere animazioni su un timer, transizioni UIView sono un'altra cosa ...).

Come rotazione è suppone a lavorare è che si ottiene un singolo -setFrame:, tutto sia impostato (e potenzialmente rerendered), e quindi le proprietà animatable sono animati. Per impostazione predefinita, ciò significa che le cose verranno ridistribuite alle nuove dimensioni, ma verranno allungate per adattarle alle vecchie dimensioni, quindi verranno animate (e separate) mentre la rotazione avanza.

Detto questo, GLKView potrebbe funzionare in modo diverso.Se stai utilizzando GLKViewController, potrebbe persino sospendere il rendering durante l'animazione di rotazione. Potresti provare a chiamare -setNeedsDisplay durante la rotazione, ma non sarà di grande aiuto dato che il frame è già impostato sul suo valore finale.

Probabilmente il modo più semplice per gestire autonomamente l'animazione di rotazione è forzare un ritrasmissione non animato al fotogramma ruotato e quindi eseguire alcune modifiche nel renderer (il bordo nero e la barra di stato si animano separatamente).

In alternativa, il modo tradizionale è di creare il tuo VC solo in verticale e gestire le notifiche di orientamento del dispositivo autonomamente, ma questo è un grande contenitore di worm (devi quindi preoccuparti dell'orientamento della barra di stato che determina cose come il tocco offset e orientamento della tastiera, e tende ad interagire "in modo interessante" quando si passa a/da altri VC).

0

Prima di tutto, assicurarsi che a un certo punto all'inizio del ciclo di vita dell'applicazione, abilitare le modifiche all'orientamento del dispositivo.

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 

Quindi quando la tua vista è istanziata registrati per una notifica come questa.

[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(deviceOrientationDidChange:) name: UIDeviceOrientationDidChangeNotification object: nil]; 

quindi implementare -deviceOrientationDidChange: nel vostro controller della vista e chiamare -setNeedsDisplay

+0

'-... DidChange' verrà chiamato dopo che è avvenuto il cambio di orientamento. E questa volta 'drawRect:' sarà chiamato anche (perché aggiorno le matrici per ora e per ogni cambio di fotogramma). Ma ho bisogno di applicare cambiamenti durante questo processo. – kpower

+0

Vedo ora. Pensavo che tu non stavi ricevendo alcuna informazione di rotazione. Ascoltare e implementare il metodo del controller di visualizzazione '- (void) willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation) interfaceOrientation duration: (NSTimeInterval) duration'. La durata ti consentirà di calcolare le animazioni durante la transizione. –

+1

Sì, lo so. E posso anche reimplementare la vista '-setFrame:' ​​- e otterrò la dimensione della vista cambia ogni passo dell'animazione. Ma non posso rispondere a questi cambiamenti - voglio dire, posso aggiornare la matrice di proiezione, ma gli aggiornamenti non saranno applicati, perché '-drawRect:' (e il corrispondente disegno GL) non sarà chiamato fino a quando l'animazione non sarà finita. – kpower

6

Questo potrebbe essere un salto nel buio dal momento che non ho alcuna esperienza con GLKit, però io ho esperienza con UIView e -drawRect:. Provare a cambiare la contentMode della vista in questione per ridisegnare:

view.contentMode = UIViewContentModeRedraw;

Questo dirà la visione che ha bisogno di ridisegnare il suo contenuto quando è confini cambiano. Altrimenti, UIView tenterà semplicemente di ridimensionarne il contenuto (l'impostazione predefinita per contentMode è UIViewContentModeScaleToFill). La ragione di questo è che è molto più semplice scalare ciò che è lì che ridisegnare il contenuto e UIView è progettato per essere il più efficiente possibile.

+0

Sfortunatamente, questo non sembra fare alcuna differenza nella pratica su un GLKView. – pmdj