W mojej implementacji podklasowałem UIView dla mojego widoku, który chcę obrócić i coś jak viewController dla tego widoku, który jest tylko podklasą NSObject.
W tym viewController robię wszystkie kontrole związane ze zmianami orientacji, podejmie decyzję, czy należy zmienić orientację moim zdaniem docelowej, a jeśli tak, to zgłoszę metoda moim zdaniem do zmiany jej orientacji.
Przede wszystkim musimy ustawić orientację całego interfejsu aplikacji na tryb portretowy, aby nasza ACCaptureVideoPreviewLayer zawsze pozostawała nieruchoma. Odbywa się to w MainViewController.h
:
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation`
{
return interfaceOrientation==UIInterfaceOrientationPortrait;
}
To nie zwraca się do wszystkich kierunkach z wyjątkiem portret.
W celu naszego zwyczaju viewController móc śledzić zmiany orientacji urządzenia musimy dokonać jej obserwatora odpowiednich powiadomień:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(orientationChanged) name:UIDeviceOrientationDidChangeNotification object:nil];
mogę umieścić te linie w sposobie mojego viewController (void)awakeFromNib
. Za każdym razem, gdy zmieni się orientacja urządzenia, zostanie wywołana metoda viewController, orientationChanged
.
Jego celem jest sprawdzenie, jaka jest nowa orientacja urządzenia, jaka była ostatnia orientacja urządzenia i podjęcie decyzji o jego zmianie. Oto realizacja:
if(UIInterfaceOrientationPortraitUpsideDown==[UIDevice currentDevice].orientation ||
lastOrientation==(UIInterfaceOrientation)[UIDevice currentDevice].orientation)
return;
[[UIApplication sharedApplication]setStatusBarOrientation:[UIDevice currentDevice].orientation animated:NO];
lastOrientation=[UIApplication sharedApplication].statusBarOrientation;
[resultView orientationChanged];
Jeśli orientacja jest taka sama jak poprzednio lub w PortraitUpsideDown, to nic nie rób. Inaczej ustawia orientację paska stanu na właściwą, dzięki czemu w przypadku połączenia przychodzącego lub kostnienia pojawi się po właściwej stronie ekranu. Następnie wywołuję metodę również w widoku docelowym, gdzie wykonuje się wszystkie odpowiednie zmiany dla nowej orientacji, takie jak obracanie, zmiana rozmiaru, przesuwanie innych elementów interfejsu w tym widoku, odpowiadających nowej orientacji.
Oto realizacja orientationChanged
w widoku docelowym:
Float32 angle=0.f;
UIInterfaceOrientation orientation=[UIApplication sharedApplication].statusBarOrientation;
switch (orientation) {
case UIInterfaceOrientationLandscapeLeft:
angle=-90.f*M_PI/180.f;
break;
case UIInterfaceOrientationLandscapeRight:
angle=90.f*M_PI/180.f;
break;
default: angle=0.f;
break;
}
if(angle==0 && CGAffineTransformIsIdentity(self.transform)) return;
CGAffineTransform transform=CGAffineTransformMakeRotation(angle);
[UIView beginAnimations:@"rotateView" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDuration:0.35f];
self.transform=transform;
[UIView commitAnimations];
Oczywiście tu można dodawać żadnych innych zmian, takich jak tłumaczenia, skalowanie różnych widoków interfejsu, które muszą odpowiedzieć na nowej orientacji i animować im.
także może nie trzeba się viewController za to, ale zrobić wszystko tylko w klasie widoku. Mam nadzieję, że ogólny pomysł jest jasny.
również nie zapomnieć, by przestać otrzymywać powiadomienia o zmianie orientacji, gdy nie trzeba ich jak:
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
[[UIDevice currentDevice]endGeneratingDeviceOrientationNotifications];
Gdyby similiar problem. Jedno oczywiste rozwiązanie jest niestety niedostępne: miałem nadzieję zaobserwować (za pomocą KVO) 'transformację' warstwy widoku 'presentationLayer' bez powodzenia - obserwacja wartości klucz-wartość nie jest dostępna podczas wykonywania animacji. Zakończono używanie (prawdopodobnie) tego samego rozwiązania, co ty: osadzanie warstwy podglądu w "UIView" i ręczne obracanie go. –
Tak, również skończyłem z ręcznym obróceniem widoku zawierającego previewLayer. Okazało się, że nie jest to zbyt skomplikowane. Stosuję CGAffineTransformMakeRotation(), a następnie zmieniam ramkę na prawidłowy rozmiar. Ale teraz mam dokładnie to, czego pragnę. – BartoNaz
@BartoNaz Miałem problemy z tym od kilku dni i wszystko, co próbuję, nie daje mi efektu camera.app, gdzie AVCaptureVideoPreviewLayer pozostaje zablokowany na widok i nie wykonuje animowanej rotacji. Czy możesz podać swój działający fragment kodu jako odpowiedź na to pytanie? Dzięki. –