2012-01-25 1 views
24

В настоящее время я использую [self presentModalViewController :newVC animated:YES]. Я хочу представить newViewcontroller слева/справа/сверху/снизу с эффектом push. Я попытался использовать CATransition, но он отображает черный экран между переходами.Анимация presentModalViewController справа/слева

+0

Для других людей с этой проблемой, я разместил решение, которое я нашел здесь: http://stackoverflow.com/questions/6876292/iphone-presentmodalviewcontroller-with-transition-from-right/10842991 # 10842991 –

ответ

1

Есть только четыре UIModalTransitionStyles:

UIModalTransitionStyleCoverVertical 
UIModalTransitionStyleFlipHorizontal 
UIModalTransitionStyleCrossDissolve 
UIModalTransitionStylePartialCurl 

Например:

UIViewController *controller = [[[MyViewController alloc] init] autorelease]; 
UIModalTransitionStyle trans = UIModalTransitionStyleFlipHorizontal; 
[UIView beginAnimations: nil context: nil]; 
[UIView setAnimationTransition: trans forView: [self window] cache: YES]; 
[navController presentModalViewController: controller animated: NO]; 
[UIView commitAnimations]; 
3

Я была такая же проблема. Допустим, вы хотите, чтобы представить контроллер представления 2 от контроллера представления 1. В первом контроллере представления используют

[self presentModalViewController: controller animated: NO]]; 

Во втором контроллере представления, в viewWillAppear: метод добавления кода

CATransition *animation = [CATransition animation]; 

    [animation setDelegate:self]; 
    [animation setType:kCATransitionPush]; 
    [animation setSubtype:kCATransitionFromRight]; 

    [animation setDuration:0.40]; 
    [animation setTimingFunction: 
    [CAMediaTimingFunction functionWithName: 
     kCAMediaTimingFunctionEaseInEaseOut]]; 


    [self.view.layer addAnimation:animation forKey:kCATransition]; 

Он будет работать хорошо. Если черный экран приходит снова, если вы используете навигацию контроллер, замените

[self.view.layer addAnimation:animation forKey:kCATransition]; 

с

[self.navigationController.view.layer addAnimation:animation forKey:kCATransition]; 
+0

попробовал это. Тем не менее проблема с черным экраном сохраняется – user1085093

+0

У меня также есть проблема с черным экраном. Перед тем, как появится модальный контроллер, появится черный экран. Кто-нибудь решил проблему? – bolonn

90

Когда присутствует:

CATransition *transition = [CATransition animation]; 
transition.duration = 0.3; 
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 
transition.type = kCATransitionPush; 
transition.subtype = kCATransitionFromRight; 
[self.view.window.layer addAnimation:transition forKey:nil]; 

[self presentModalViewController:viewCtrl animated:NO]; 

Когда отклонять:

CATransition *transition = [CATransition animation]; 
transition.duration = 0.3; 
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 
transition.type = kCATransitionPush; 
transition.subtype = kCATransitionFromLeft; 
[self.view.window.layer addAnimation:transition forKey:nil]; 
[self dismissModalViewControllerAnimated:NO]; 
+0

Отлично. Это правильный ответ. – rmvz3

+5

Это, похоже, больше не работает на iOS 8, так как представляющий VC движется вместо представленного. Любая идея, как это исправить? – Maiaux

+1

¿Как я могу удалить эффекты затухания? – jalopezsuarez

-1

Вы может установить transitioningDelegate на контроллере представления, который вы хотите представить. Вы должны соответствовать протоколам UIViewControllerTransitioningDelegate и UIViewControllerAnimatedTransitioning. И, реализуя animateTransition(transitionContext: UIViewControllerContextTransitioning), вы можете анимировать либо просмотр представлений диспетчеров.

Функция, которая выполняет переход

class fromViewController : UIViewController { 
    let transitionManager = TransitionManager() 

    func transitionToViewController() { 
     toController.transitioningDelegate = transitionManager 
     presentViewController(toController, animated: true, completion: nil) 
    } 
} 

Тогда TransitionManager выглядит следующим образом:

import UIKit 

class TransitionManager : UIPercentDrivenInteractiveTransition { 
    var presenting = false 
} 

// MARK: UIViewControllerAnimatedTransitioning 
extension TransitionManager : UIViewControllerAnimatedTransitioning { 
    func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 
     let container = transitionContext.containerView() 
     let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)! 
     let toView = transitionContext.viewForKey(UITransitionContextToViewKey)! 

     let offScreenRight = CGAffineTransformMakeTranslation(container.frame.width, 0) 
     let offScreenLeft = CGAffineTransformMakeTranslation(-container.frame.width, 0) 

     toView.transform = self.presenting ? offScreenRight : offScreenLeft 

     container.addSubview(toView) 
     container.addSubview(fromView) 
     let duration = self.transitionDuration(transitionContext) 

     UIView.animateWithDuration(duration, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 0.8, options: nil, animations: { 
      fromView.transform = self.presenting ? offScreenLeft : offScreenRight 
      toView.transform = CGAffineTransformIdentity 

      }, completion: { finished in 
      transitionContext.completeTransition(true) 
     }) 
    } 


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


// MARK: UIViewControllerTransitioningDelegate 
extension TransitionManager : UIViewControllerTransitioningDelegate { 
    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 
    } 
} 
+0

Не работает. Случай 'self.presenting == false' приводит к черному экрану с неправильным фреймом – Barry

+0

@Barry Это работает для меня, не используя segues, а скорее ручные переходы между контроллерами в разных раскадровках. По взглядам на код, который вы выложили выше, вы пытаясь переопределить push-переход UINavigationController. У вас есть выбор в раскадровке, который нужно нажимать, а не присутствовать? –

1

После X> = 4 часа работы, это работает без "разрыва" или других фоновых артефактов:

class AboutTransition: NSObject, UIViewControllerAnimatedTransitioning { 

    let presenting: Bool 
    let duration: NSTimeInterval 

    init(presenting: Bool, duration: NSTimeInterval = 0.25) { 
     self.presenting = presenting 
     self.duration = duration 
    } 

    @objc func transitionDuration(ctx: UIViewControllerContextTransitioning) -> NSTimeInterval { 
     return duration 
    } 

    @objc func animateTransition(ctx: UIViewControllerContextTransitioning) { 
     let duration = transitionDuration(ctx) 
     let containerView = ctx.containerView() 
     let fromViewController = ctx.viewControllerForKey(UITransitionContextFromViewControllerKey)! 
     let toViewController = ctx.viewControllerForKey(UITransitionContextToViewControllerKey)! 
     let fromView = fromViewController.view // 7.0 & 8.0 compatible vs. viewForKey: 
     let toView = toViewController.view  // 7.0 & 8.0 compatible vs. viewForKey: 

     containerView.addSubview(fromView) 
     containerView.addSubview(toView) 

     let offScreenRight = CGAffineTransformMakeTranslation(containerView.frame.width, 0) 
     let offScreenLeft = CGAffineTransformMakeTranslation(-containerView.frame.width, 0) 

     fromView.transform = CGAffineTransformIdentity 
     toView.transform = self.presenting ? offScreenRight : offScreenLeft 

     UIView.animateWithDuration(duration, delay:0, options:UIViewAnimationOptions(0), animations: { 
      fromView.transform = self.presenting ? offScreenLeft : offScreenRight 
      toView.transform = CGAffineTransformIdentity 

     }, completion: { (finished: Bool) in 
      ctx.completeTransition(finished) 
      if finished { 
       fromView.removeFromSuperview() 
       fromView.frame = toView.frame // reset the frame for reuse, otherwise frame transforms will accumulate 
      } 
     }) 
    } 
} 

Затем в AppDelegate.swift:

@UIApplicationMain 
class AppDelegate: UIResponder, UIApplicationDelegate, UINavigationControllerDelegate { 

    lazy var window: UIWindow? = { 
     return UIWindow(frame: UIScreen.mainScreen().bounds) 
    }() 

    lazy var storyboard = UIStoryboard(name: "Main", bundle: nil) 

    lazy var nav: UINavigationController = { 
     var r = self.storyboard.instantiateInitialViewController() as! UINavigationController 
     r.delegate = self 
     return r 
    }() 

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 
     self.window!.rootViewController = nav 
     self.window!.makeKeyAndVisible() 

     // .. other setup 

     return true 
    } 

    // ... 


    // MARK: - UINavigationControllerDelegate 

    func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { 
     // Example of a SettingsViewController which pushes AboutViewController 
     if fromVC is SettingsViewController && toVC is AboutViewController { // Push to About 
      return AboutTransition(presenting: true) 
     } else if fromVC is AboutViewController && toVC is SettingsViewController { // Pop to Settings 
      return AboutTransition(presenting: false) 
     } 
     return nil 
    } 
} 

Это предполагает приложение использует раскадровку по умолчанию с начальным VC как UINavigationController