2013-03-07 22 views
5

Mam aplikację opartą na GLKit z kilkoma prostymi obiektami wyświetlanymi.GLKit's -drawRect: nie jest wywoływany podczas obracania ekranu

Wszystko działa poprawnie, z wyjątkiem obracania ekranu, podczas którego GLKView nie jest aktualizowany (nie jest wywoływany). W związku z tym macierz projekcji rotacyjnej nie jest aktualizowana zgodnie z dynamicznie zmieniającymi się rozmiarami ekranów, a obiekt wygląda źle (rozciągnięty).

+0

Czy używasz cieniowania lub GLKBaseEffect? –

+0

Próbowałem zarówno: "GLKBaseEffect", jak i własnych shaderów - ten sam wynik. '-drawRect:' zostanie wywołany po zakończeniu animacji - więc wszelkie renderowanie GL (które zwykle tam umieszczamy) zostanie zawieszone do tego momentu. – kpower

+1

Ok. Myślałem, że może właściwość projectionMatrix na GLKBaseEffect była błędna. Pomyślę ... –

Odpowiedz

1

Po prostu nie działa to, jak działają animacje UIKit. I sort-of wyjaśnić, jak połowa z nich pracuje w this answer, ale postaram się podsumować odpowiednie bity:

  • Wszystko jest teksturą prostokąta. (Istnieje kilka wyjątków, jak na przykład CAShapeLayer, ale jest to w większości przypadków prawdziwe.) Właściwości
  • UIView są powiązane z właściwościami "drzewa modelu" CALayera. Zmieniają one natychmiastowo.
  • Animacje działają poprzez animowanie właściwości drzewa prezentacji od wartości początkowej do bieżącej wartości modelu.
  • Początkową wartością animacji jest domyślnie poprzednia wartość modelu. Podanie UIViewAnimationOptionBeginFromCurrentState powoduje, że używa on bieżącej wartości prezentacji.

Istnieje oczywiście kilka wyjątków (CAShapeLayer wydaje się być bardziej niż teksturą rect, UIScrollView powoduje przewijanie animacji na zegar, przejścia UIView to zupełnie inna sprawa ...).

Jak rotacja jest powinien do pracy jest to, że można dostać jeden -setFrame:, wszystko jest rozplanowane (i potencjalnie rerendered), a następnie właściwości animatable są animowane. Domyślnie oznacza to, że rzeczy będą poddawane nowym wymiarom, ale rozciągnięte, aby pasowały do ​​starych wymiarów, a następnie animowane (i rozprężane) w miarę postępu rotacji.

To powiedziawszy, GLKView może działać inaczej.Jeśli używasz GLKViewController, może nawet zawiesić rendering podczas animacji rotacji. Możesz spróbować wywołać -setNeedsDisplay podczas rotacji, ale to niewiele pomoże, ponieważ ramka jest już ustawiona na jej wartość końcową.

Najprawdopodobniej najłatwiejszym sposobem radzenia sobie z animacją rotacji jest zmuszenie nie-animowanego przekaźnika do obróconej ramki, a następnie wykonanie fragmentacji w rendererze (jednak czarna ramka i pasek stanu są osobno animowane).

Alternatywnie, tradycyjny sposób polega na tym, aby uzyskać tylko portret VC i obsługiwać powiadomienia o orientacji urządzenia samemu, ale jest to duża puszka robaków (musisz wtedy martwić się o orientację paska stanu, która określa rzeczy takie jak dotyk przesunięcie i orientacja klawiatury, i ma tendencję do interakcji "interesująco" podczas przechodzenia do/z innych VC).

0

Przede wszystkim upewnij się, że w pewnym momencie na początku cyklu życia aplikacji włącz zmiany orientacji urządzenia.

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 

Następnie, gdy twój widok zostanie utworzony, zarejestruj się, aby otrzymać powiadomienie.

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

Następnie wdrożyć -deviceOrientationDidChange: w kontrolerze widoku i nazywają -setNeedsDisplay

+0

'' 'DidChange' zostanie wywołany po zmianie orientacji. I tym razem 'drawRect:' będzie również wywoływany (ponieważ aktualizuję macierze według czasu i każdej zmiany ramki). Ale muszę zastosować zmiany podczas tego procesu. – kpower

+0

Teraz widzę. Chciałem powiedzieć, że w ogóle nie otrzymałeś żadnych informacji o rotacji. Odsłuchaj i zaimplementuj metodę kontrolera widoku '- (void) willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation) interfaceOrientation duration: (NSTimeInterval) duration'. Czas trwania pozwoli ci obliczyć twoje animacje podczas przejścia. –

+1

Tak, wiem. Mogę też ponownie zaimplementować widok '-setFrame:' ​​- i zmieni rozmiar widoku każdego etapu animacji. Ale nie mogę odpowiedzieć na te zmiany - mam na myśli, że mogę zaktualizować macierz projekcji, ale aktualizacje nie zostaną zastosowane, ponieważ '-drawRect:' (i odpowiadający rysunek GL) nie będą wywoływane dopóki animacja nie zostanie zakończona. – kpower

6

To może być strzał w ciemno, ponieważ nie mam żadnego doświadczenia z GLKit, jednak ja mam doświadczenia z UIView i -drawRect:. Spróbuj zmienić contentMode poglądu w kwestii odświeżenia:

view.contentMode = UIViewContentModeRedraw;

to powie, że potrzebuje odświeżenia jego zawartość, kiedy to granice zmienić. W przeciwnym razie, UIView po prostu spróbuje przeskalować zawartość (domyślnie dla contentMode jest UIViewContentModeScaleToFill). Powodem tego jest to, że o wiele łatwiej jest skalować to, co tam jest, niż przerysowywać zawartość, a UIView jest tak wydajny, jak to tylko możliwe.

+0

Niestety, nie wydaje się to mieć żadnego znaczenia w praktyce na GLKView. – pmdj