2015-08-12 23 views
7

Używam niestandardowych przejść do wyświetlania pełnoekranowego widoku gry modalnej. Gdy użytkownik uruchamia grę, kontroler widoku głównego skaluje się "w" na ekranie, podczas gdy pełnoekranowy kontroler widoku z gry przesuwa się z większej skali w dół na wyświetlacz, przechodząc od 0% krycia do 100% krycia. Prosty!Niestandardowe przejścia i obroty iOS

Przejście wygląda świetnie i działa dobrze, również poprawnie odwracając animację podczas zamykania kontrolera widoku gry.

Problem polega na tym, że jeśli urządzenie zostanie obrócone na , gdy kontroler widoku pełnoekranowego zostanie wyświetlony, po powrocie do kontrolera widoku głównego, układ jest cały zawiły. A dalsza rotacja nie rozwiązuje problemu, układ jest nieprzyzwoity i pozostaje nieprzyjemny.

Jeśli wyłączę niestandardowe przejście, ten problem zniknie. Ponadto, jeśli zachowam niestandardowe przejście, ale wyłączam połączenia, ustawiając CATransform3D w moich widokach źródłowym i docelowym w animacji przejścia, problem znika ponownie.

Oto mój przenoszący delegat:

class FullscreenModalTransitionManager: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate { 

    private var presenting:Bool = true 

    // MARK: UIViewControllerAnimatedTransitioning protocol methods 

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 

     // get reference to our fromView, toView and the container view that we should perform the transition in 
     let container = transitionContext.containerView() 
     let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)! 
     let toView = transitionContext.viewForKey(UITransitionContextToViewKey)! 

     let scale:CGFloat = 1.075 
     //let bigScale = CGAffineTransformMakeScale(scale, scale) 
     //let smallScale = CGAffineTransformMakeScale(1/scale,1/scale) 
     let bigScale = CATransform3DMakeScale(scale, scale, 1) 
     let smallScale = CATransform3DMakeScale(1/scale, 1/scale, 1) 
     let smallOpacity:CGFloat = 0.5 
     let presenting = self.presenting 

     if presenting { 

      // when presenting, incoming view must be on top 
      container.addSubview(fromView) 
      container.addSubview(toView) 

      toView.layer.transform = bigScale 
      toView.opaque = false 
      toView.alpha = 0 

      fromView.layer.transform = CATransform3DIdentity 
      fromView.opaque = false 
      fromView.alpha = 1 
     } else { 

      // when !presenting, outgoing view must be on top 
      container.addSubview(toView) 
      container.addSubview(fromView) 

      toView.layer.transform = smallScale 
      toView.opaque = false 
      toView.alpha = smallOpacity 

      fromView.layer.transform = CATransform3DIdentity 
      fromView.opaque = false 
      fromView.alpha = 1 
     } 


     let duration = self.transitionDuration(transitionContext) 

     UIView.animateWithDuration(duration, 
      delay: 0.0, 
      usingSpringWithDamping: 0.7, 
      initialSpringVelocity: 0, 
      options: nil, 
      animations: { 

       if presenting { 
        fromView.layer.transform = smallScale 
        fromView.alpha = smallOpacity 
       } else { 
        fromView.layer.transform = bigScale 
        fromView.alpha = 0 
       } 

      }, 
      completion: nil) 

     UIView.animateWithDuration(duration, 
      delay: duration/6, 
      usingSpringWithDamping: 0.7, 
      initialSpringVelocity: 0.5, 
      options: nil, 
      animations: { 
       toView.layer.transform = CATransform3DIdentity 
       toView.alpha = 1 
      }, 
      completion: { finished in 
       transitionContext.completeTransition(true) 
      }) 
    } 

    func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval { 
     return 0.5 
    } 

    // MARK: UIViewControllerTransitioningDelegate protocol methods 

    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { 
     self.presenting = true 
     return self 
    } 

    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 
     self.presenting = false 
     return self 
    } 
} 

A dla odniesienia wzrokowego, oto co mój główny widok kontroler zwykle wygląda następująco:

Correct layout for my root view controller

A dla odniesienia wzrokowego, oto co moje Kontrola widoku root wygląda tak, jak obracam urządzenie (przynajmniej raz) w widoku gry i wracam do kontrolera widoku głównego.

Broken layout, after rotating device while in fullscreen game view and returning to root view

I ostatnia uwaga - na wszelki wypadek dzwoni żadnych dzwony - Używam klas autolayout i wielkość rozplanować moim zdaniem główny kontroler.

Dzięki,

Odpowiedz

4

przypadkowo zorientowaliśmy się, robiąc ręcznej kod układu na widoki z nie-tożsamości przemienia. Włącza się, jeśli widok nie zawiera przekształcenia tożsamościowego, normalny kod układu kończy się niepowodzeniem.

Poprawka, w mojej delegacji do przeniesienia polegała na przeniesieniu widoku, a w animacji, kompletny oddzwonił, aby przekształcić ją w tożsamość (ponieważ widok ten jest niewidoczny na końcu animacji i za nowym widokiem, nie ma to żadnego wpływu na wygląd)

UIView.animateWithDuration(duration, 
    delay: 0.0, 
    usingSpringWithDamping: 0.7, 
    initialSpringVelocity: 0, 
    options: nil, 
    animations: { 

     if presenting { 
      fromView.transform = smallScale 
      fromView.alpha = smallOpacity 
     } else { 
      fromView.transform = bigScale 
      fromView.alpha = 0 
     } 

    }, 
    completion: { completed in 
     // set transform of now hidden view to identity to prevent breakage during rotation 
     fromView.transform = CGAffineTransformIdentity 
    }) 
+0

ta działa tylko wtedy, gdy fromVC nie widoczne po transformacji. Zobacz moją odpowiedź – daleijn

+0

Skorzystaj z odpowiedzi zarówno tej, jak i @agilityvision! Po zakończeniu przejścia musisz zresetować 'transform' do tożsamości, a kiedy rozpoczniesz przejście, musisz ustawić ramkę na finalFrame, a następnie zastosować transformację. – kientux

25

Miałem podobny problem, napisałem niestandardowe przejście dla push i pop na kontrolerze nawigacyjnym. Jeśli obróciłeś urządzenie po naciśnięciu przycisku, po powrocie do głównego kontrolera widoku jego ramka pozostanie niezmieniona.


problem

enter image description here


Rozwiązanie

Cel C

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext { 

    // ViewController Reference 
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 

    // Fix layout bug in iOS 9+ 
    toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController]; 

    // The rest of your code ... 
} 

Swift 3,0

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 

    // ViewController reference 
    let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)! 

    // Fix layout bug in iOS 9+ 
    toViewController.view.frame = transitionContext.finalFrame(for: toViewController) 

    // The rest of your code ... 
} 
+0

Otrzymałem ten sam problem na iOS 10.0, a to naprawiło. Dzięki. –

1

końcu znalazłem rozwiązanie dla tego problemu. Musisz poprawić kod @agilityvision. Trzeba dodać wartość BOOL, coś closeVCNow wskazującą chcesz zamknąć VC, aw animateTransition: w bloku animacji zrobić:

if (self.closeVCNow) { 
     toVC.view.transform = CGAffineTransformIdentity; 
     toVC.view.frame = [transitionContext finalFrameForViewController:toVC]; 
     self.closeVCNow = NO; 
    } 
Powiązane problemy