2016-06-17 22 views
6

Pracuję nad aplikacją fotograficzną, która umożliwia robienie zdjęć w orientacji pionowej lub poziomej. Ze względu na wymagania projektu nie mogę pozwolić autorotacji na orientację urządzenia, ale obrót musi być obsługiwany.Orientacja sterownika Force View w systemie iOS 9

Przy użyciu następujących metod Orientacja:

override func shouldAutorotate() -> Bool { 
    return true 
} 

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { 
    if self.orientation == .Landscape { 
     return UIInterfaceOrientationMask.LandscapeRight 
    } else { 
     return UIInterfaceOrientationMask.Portrait 
    } 
} 

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation { 
    if self.orientation == .Landscape { 
     return UIInterfaceOrientation.LandscapeRight 
    } else { 
     return UIInterfaceOrientation.Portrait 
    } 
} 

jestem w stanie ustawić rotację poprawnie na rynek. Zmieniając wartość orientacji i wywołując UIViewController.attemptRotationToDeviceOrientation() jestem w stanie obsłużyć obrót do nowego pożądanego interfejsu. Jednak ten obrót występuje tylko wtedy, gdy użytkownik faktycznie przenosi swoje urządzenie. Potrzebuję tego automatycznie.

mogę zadzwonić: UIDevice.currentDevice().setValue(targetOrientation.rawValue, forKey: "orientation") wymusić zmianę, ale to powoduje inne efekty uboczne, ponieważ UIDevice.currentDevice().orientation zwraca tylko setValue od tego momentu. (i jest bardzo brudny)

Czy jest coś, czego mi brakuje? Przyjrzałem się zamykaniu i uruchamianiu nowego kontrolera widoku, ale ma to inne problemy, takie jak stały błąd interfejsu podczas zamykania i natychmiastowy prezentowanie nowego kontrolera widoku.

EDIT:

Następujące metody nie działa dla mnie:

EDIT 2:

Myśli o potencjalnych rozwiązań:

  1. zestaw orientacja bezpośrednio (z setValue) i radzić sobie ze wszystkimi skutkami ubocznymi to przedstawia na iOS 9 (nie do przyjęcia)

  2. mogę korzystać z obecnego rozwiązania i wskazywać, że użytkownik musi obrócić urządzenie . Po fizycznym obróceniu urządzenia interfejs użytkownika obraca się, a następnie prawidłowo blokuje. (słaby interfejs użytkownika)

  3. Mogę znaleźć rozwiązanie, które zmusza odświeżenie orientacji i obraca się bez fizycznego działania. (o co pytam i czego szukam)

  4. Wykonuj wszystko ręcznie. Mogę zablokować interfejs w układzie pionowym lub poziomym, a także ręcznie obrócić i zmienić rozmiar widoku kontenera. Jest to "brudne", ponieważ powoduje rezygnację z wszystkich funkcji autolayout klasy wielkości i powoduje dużo cięższy kod. Próbuję tego uniknąć.

+1

To jest odpowiedź typu Objective-C: http://stackoverflow.com/questions/2689598/forcing-uiinterfaceorientation-changes-on-iphone?rq=1, ale uważam, że interfejs API jest taki sam dla Swift; czy to zadziała dla ciebie? – fullofsquirrels

+1

Byłoby to jednak, ale metody te są nieaktualne w iOS 9. Istnieje wiele rozwiązań, które kiedyś istniały, mam problem ze znalezieniem, który nadal działa. Nasze potrzeby są bardzo zdefiniowane i mają sens, ale są nieco sprzeczne z obecnym wzorcem (z powodu). W tym przypadku, pozwalanie użytkownikowi na wybór orientacji nie jest możliwe. –

+0

Ha, właśnie zobaczyłem deprecation teraz, bummer. Czy Twój VC jest zawarty w kontrolerze nawigacyjnym lub pasku kart? Odpowiedź Korey'ego Hintona tutaj: http://stackoverflow.com/questions/26357162/how-to-force-view-controller-orientation-in-ios-8- próbuje rozwiązać ten konkretny przypadek, ale nie próbowałem go . – fullofsquirrels

Odpowiedz

3

udało mi się znaleźć rozwiązanie z pomocą tej odpowiedzi: Programmatic interface orientation change not working for iOS

Moja logika orientacja baza jest następujący:

// Local variable to tracking allowed orientation. I have specific landscape and 
// portrait targets and did not want to remember which I was supporting 
enum MyOrientations { 
    case Landscape 
    case Portrait 
} 
var orientation: MyOrientations = .Landscape 

// MARK: - Orientation Methods 

override func shouldAutorotate() -> Bool { 
    return true 

} 

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { 
    if self.orientation == .Landscape { 
     return UIInterfaceOrientationMask.LandscapeRight 
    } else { 
     return UIInterfaceOrientationMask.Portrait 
    } 
} 

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation { 
    if self.orientation == .Landscape { 
     return UIInterfaceOrientation.LandscapeRight 
    } else { 
     return UIInterfaceOrientation.Portrait 
    } 
} 

// Called on region and delegate setters 
func refreshOrientation() { 
    if let newOrientation = self.delegate?.getOrientation() { 
     self.orientation = newOrientation 
    } 
} 

wtedy, kiedy chcę, aby odświeżyć orientacji, mam następujące:

// Correct Orientation 
let oldOrientation = self.orientation 
self.refreshOrientation() 
if self.orientation != oldOrientation { 
    dispatch_async(dispatch_get_main_queue(), { 
     self.orientationRefreshing = true 

     let vc = UIViewController() 

     UIViewController.attemptRotationToDeviceOrientation() 

     self.presentViewController(vc, animated: false, completion: nil) 

     UIView.animateWithDuration(0.3, animations: { 
      vc.dismissViewControllerAnimated(false, completion: nil) 
     }) 
    }) 
} 

Rozwiązanie to ma efekt uboczny powoduje view[Will/Did]Appear i view[Will/Did]Disappear wystrzelić wszystkie naraz. Używam lokalnej zmiennej orientationRefreshing do zarządzania, które aspekty tych metod są wywoływane ponownie.

3

Zetknąłem się z tym problemem w przeszłości, ja sam. Udało mi się go rozwiązać za pomocą prostej pracy (i GPUImage). Mój kod znajduje się w Objective-C, ale jestem pewien, że nie będziesz miał problemu z przetłumaczeniem go na Swift.

zacząłem obsługiwane przez ustawienie obrotów projektu, aby wszystko, co miałem nadzieję na wsparcie i wtedy nadrzędne tych samych metod UIViewController:

-(BOOL)shouldAutorotate { 
    return TRUE; 
} 

-(NSUInteger)supportedInterfaceOrientations { 
    return UIInterfaceOrientationMaskPortrait; 
} 

który umożliwia urządzenie do obracania ale będzie utrzymywać się w trybie portretowym. Następnie rozpoczął obserwację do obrotów urządzenia:

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

następnie zaktualizowany interfejs użytkownika, jeśli urządzenie było w trybie pionowym lub poziomym:

-(void)adjustForRotation:(NSNotification*)notification 
{ 
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; 

    switch (orientation) { 
     case UIDeviceOrientationLandscapeLeft: 
     { 
      // UPDATE UI 
     } 
      break; 
     case UIDeviceOrientationLandscapeRight: 
     { 
      // UPDATE UI 
     } 
      break; 
     default: // All other orientations - Portrait, Upside Down, Unknown 
     { 
      // UPDATE UI 
     } 
      break; 
    } 
} 

I wreszcie, GPUImage świadczonych obraz ze względu na orientację urządzenia.

[_gpuImageStillCamera capturePhotoAsImageProcessedUpToFilter:last_f 
               withCompletionHandler:^(UIImage *processedImage, NSError *error) { 
    // Process the processedImage 
}]; 
+0

Jak oceniasz obsługę interfejsu użytkownika? Czy ręcznie skalujesz i obracasz interfejsem kontenera? –

+0

Chciałbym zastosować CGAffineTransform na elementy interfejsu użytkownika @NathanTornquist, więc obrót – achi

+0

Ponadto, bardzo polecam za pomocą GPUImage. Jest to jeden z większych wkładów do ekosystemu Open Source iOS! Jeśli poważnie myślisz o użyciu tej metody, z przyjemnością przedstawię moje rozwiązanie bardziej szczegółowo. – achi

0

Więc spojrzał na prywatnych nagłówkach UIDevice, i wydaje się, że istnieją dwa ustawiaczy i dwie definicje własności, dla orientacji, która obecnie jest zaskakujący mnie. To, co widziałem ...

@property (nonatomic) int orientation; 
@property (nonatomic, readonly) int orientation; 

- (void)setOrientation:(int)arg1; 
- (void)setOrientation:(int)arg1 animated:(BOOL)arg2; 

Więc kiedy zobaczyłem, że użyłeś setValue:forKey:, chciałem zobaczyć było syntetyzowane setter i getter i jestem szczerze nie 100% pewien, co do których jedna jest ustawiona , i który z nich jest potwierdzany przez urządzenie ... Próbowałem w aplikacji demo, aby użyć setValue:forKey: bezskutecznie, ale użyłem tej sztuczki z jednej z moich przeszłych aplikacji, i to od razu zrobiło sztuczkę :) Mam nadzieję, że to pomaga

UIDevice.currentDevice().performSelector(Selector("setOrientation:"), withObject: UIInterfaceOrientation.Portrait.rawValue) 
+0

Podczas gdy to działa, jest to prywatny interfejs API i bardzo solidny sposób na odrzucenie mojej aplikacji. –

+0

Tak naprawdę pisałem przez proces recenzji z tym wcześniej, około trzy lata temu na TMGGO, kiedy zmuszałem odtwarzacz wideo do orientacji. Technicznie, 'setValue: forKey:', faktycznie wywołuje 'setOrientation:' w tle, więc dla mnie byłbym zaskoczony, że zostałoby to odrzucone, ponieważ technicznie robisz to samo, na tyle dziwne, że wyniki są różne: / – AntonTheDev