2016-07-14 125 views
16

Questa domanda è strettamente su iOS9 +In 7.3/9/2 + Swift come disabilitare l'animazione di rotazione, quando il dispositivo ruota?

Diciamo che avete un app moderno ordinario (autolayout, storyboard, universale), che fa permettere a tutti i quattro posizioni di rotazione

enter image description here

si vuole che AutoRotate nel normale modo, quindi cambierà i tuoi nuovi layout basati su vincoli quando l'utente ruota il dispositivo da orizzontale a verticale

Ma si desidera semplicemente NO animazione durante la rotazione del dispositivo dell'utente. Volete semplicemente "fare clic" sul nuovo layout laterale o verticale.

L'unico modo che ho potuto ottenere questo è aggiungendo:

override func viewWillTransitionToSize(size:CGSize, 
     withTransitionCoordinator coordinator:UIViewControllerTransitionCoordinator) 
    { 
    coordinator.animateAlongsideTransition(nil, completion: 
     {_ in 
     UIView.setAnimationsEnabled(true) 
     }) 
    UIView.setAnimationsEnabled(false) 
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator); 
    } 

a un controller vista, un massimo o quasi massimo VC che detiene il resto delle viste contenitore o qualunque in la scena.

Questa è fondamentalmente la stessa antica idea dell'uso di willRotateToInterfaceOrientation/didRotateFromInterfaceOrientation (entrambi ora inutilizzabili nel moderno iOS) per attivare le animazioni on-off.

Tuttavia ci sono molti problemi

  • questo non funziona AppWide, è un casino, è scena a base di

  • sembra molto inappropriato girare appena fuori tutte le animazioni

  • è possibile vedere tutti i tipi di pista

Questa domanda è strettamente su iOS9 +

In questi giorni, c'è un modo migliore per disattivare le animazioni di rotazione in un'app che supporta paesaggio/ritratto ???

Questa domanda è strettamente su iOS9 +

+2

Per quale versione di iOS è? –

+0

Ciao @LukeVanIn grazie, certamente iOS9. Nota la prima frase! – Fattie

+0

Funziona sul simulatore ma non su un dispositivo reale (ipad). 'UIView.areAnimationsEnabled()' restituisce 'true' all'interno del blocco di animazione, che mi lascia perplesso (come in effetti è disabilitato prima). Deve esserci un problema di temporizzazione con il blocco dell'animazione di rotazione ... (doc di "setAnimationsEnabled" afferma: "_ Questo metodo riguarda solo le animazioni inviate dopo la chiamata. Se si chiama questo metodo mentre le animazioni esistenti sono in esecuzione, tali animazioni continuano in esecuzione fino a raggiungere il loro endpoint naturale._ ") – lazi74

risposta

5

È possibile utilizzare il metodo Swizzling.

Ciò significa che stanno per cambiare le chiamate a "viewWillTransitionToSize" su qualsiasi controller di visualizzazione nell'applicazione per chiamare invece "genericViewWillTransitionToSize".
In questo modo non è necessario utilizzare sottoclasse o codice ripetuto sull'applicazione.

Con quello triste, dovresti essere molto furbo con il brivido, con un grande potere derivano grandi responsabilità. Metti la classe in un posto che tu, o il prossimo programmatore dopo di te, saprai come trovarla, quando vorrai restituire le animazioni di rotazione per visualizzare i controller.

extension UIViewController { 

    public override static func initialize() { 
     struct Static { 
      static var token: dispatch_once_t = 0 
     } 

     dispatch_once(&Static.token) { 
      let originalSelector = #selector(UIViewController.viewWillTransitionToSize(_:withTransitionCoordinator:)) 
      let swizzledSelector = #selector(UIViewController.genericViewWillTransitionToSize(_:withTransitionCoordinator:)) 

      let originalMethod = class_getInstanceMethod(self, originalSelector) 
      let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) 

      let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) 

      if didAddMethod { 
       class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) 
      } else { 
       method_exchangeImplementations(originalMethod, swizzledMethod); 
      } 
     } 
    } 

    // MARK: - Method Swizzling 
    func genericViewWillTransitionToSize(size:CGSize, 
              withTransitionCoordinator coordinator:UIViewControllerTransitionCoordinator) 
    { 
     self.genericViewWillTransitionToSize(size, withTransitionCoordinator: coordinator) 
     coordinator.animateAlongsideTransition(nil, completion: 
      {_ in 
       UIView.setAnimationsEnabled(true) 
     }) 
     UIView.setAnimationsEnabled(false) 
    } 
} 
+0

tiger coding ... – Fattie

+0

Questa è la risposta corretta :) – Ori

+0

Questo ha funzionato per me –

5

Per quanto ne so, non c'è modo migliore per farlo.

Sebbene sia possibile dichiarare una classe separata con questo metodo e rendere tutti i controller di visualizzazione nella propria app le sue sottoclassi.

class NoRotateAnimationVC: UIViewController { 
    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { 
     super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) 
     UIView.setAnimationsEnabled(false) 
     coordinator.notifyWhenInteractionEndsUsingBlock {_ in UIView.setAnimationsEnabled(true)} 
    } 
} 

Quando si ruota il dispositivo, tutti i controller di vista le cui opinioni bisogno di cambiare le loro dimensioni ricevere viewWillTransitionToSize chiamata di metodo.

È necessario dichiarare questa nuova classe una volta nell'app e quindi modificare tutte le dichiarazioni del controller di visualizzazione dalla classe MyViewController: UIViewController a MyViewController: NoRotateAnimationVC.

L'implementazione fornita disabilita tutte le animazioni e le riattiva dopo la transizione. Pertanto, se si esegue l'override di questo metodo in un solo controller di visualizzazione, a condizione che la sua vista modifichi le dimensioni come risultato di una rotazione, disabiliterà le animazioni di rotazione ovunque. Ma se quel controller della vista non è attivo, le animazioni non saranno disabilitate.

+0

È necessario dichiarare questa nuova classe una volta nell'app e quindi modificare tutte le dichiarazioni del controller di visualizzazione da' classe MyViewController: UIViewController {...} 'a' MyViewController: NoRotateAnimationVC { ...} ' – bzz

+0

Ah, stai dicendo che OGNI controller di visualizzazione deve farlo. Giusto. È interessante notare che ho trovato se ne scegli uno - penso anche a caso - funziona. (Non ho idea se questo potrebbe introdurre ulteriori problemi.) Grazie ancora – Fattie

+1

@JoeBlow Quando si ruota il dispositivo, tutti i controller di vista le cui viste devono cambiare le loro dimensioni ricevono il richiamo del metodo 'viewWillTransitionToSize'. L'implementazione fornita disabilita tutte le animazioni e le riattiva dopo la transizione. Pertanto, se si esegue l'override di questo metodo in un solo controller di visualizzazione, a condizione che la sua vista modifichi le dimensioni come risultato di una rotazione, disabiliterà le animazioni di rotazione ovunque. Ma se quel controller della vista non è attivo, le animazioni non saranno disabilitate. – bzz

Problemi correlati