web-dev-qa-db-ja.com

右/左からpresentModalViewControllerをアニメーション化

現在[self presentModalViewController :newVC animated:YES]を使用しています。newViewcontrollerを左/右/上/下からプッシュ効果で表示したいと考えています。 CATransitionを使用しようとしましたが、トランジションの合間に黒い画面が表示されます。

25
user1085093

存在する場合:

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];
90
wcrane

私も同じ問題を抱えていました。たとえば、ビューコントローラ1からビューコントローラ2を提示するとします。最初のビューコントローラでは、

 [self presentModalViewController: controller animated: NO]];

2番目のビューコントローラーの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];
3
rakeshNS

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

Swift 3/4の更新

class LTRTransition: NSObject, UIViewControllerAnimatedTransitioning
{ 
let presenting: Bool
let duration: TimeInterval

init(presenting: Bool, duration: TimeInterval = Theme.currentTheme.animationDuration) {
    self.presenting = presenting
    self.duration = duration
}

@objc func transitionDuration(using ctx: UIViewControllerContextTransitioning?) -> TimeInterval {
    return duration
}

@objc func animateTransition(using ctx: UIViewControllerContextTransitioning) {
    let duration = transitionDuration(using: ctx)
    let containerView = ctx.containerView
    let fromViewController = ctx.viewController(forKey: UITransitionContextViewControllerKey.from)!
    let toViewController = ctx.viewController(forKey: UITransitionContextViewControllerKey.to)!
    guard let fromView = fromViewController.view, // 7.0 & 8.0 compatible vs. viewForKey:
        let toView = toViewController.view     // 7.0 & 8.0 compatible vs. viewForKey:
        else {
            assertionFailure("fix this")
            return
    }
    containerView.addSubview(fromView)
    containerView.addSubview(toView)

    let offScreenRight = CGAffineTransform(translationX: containerView.frame.width, y: 0)
    let offScreenLeft = CGAffineTransform(translationX: -containerView.frame.width, y: 0)

    fromView.transform = CGAffineTransform.identity
    toView.transform = self.presenting ? offScreenRight : offScreenLeft

    UIView.animate(withDuration: duration, delay:0, options:UIViewAnimationOptions(rawValue: 0), animations: {
        fromView.transform = self.presenting ? offScreenLeft : offScreenRight
        toView.transform = CGAffineTransform.identity

    }, completion: { (finished: Bool) in
        ctx.completeTransition(finished)
        if finished {
            fromView.removeFromSuperview()
             // this screws up dismissal. at least on ios10 it does               fromView.frame = toView.frame // reset the frame for reuse, otherwise frame transforms will accumulate
        }
    })
}
}

また、VCのtransitioniningDelegate実装がプッシュ/却下されます。

extension WhateverVCyouArePresentingFrom: UIViewControllerTransitioningDelegate
{
public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning?
{
    return LTRTransition(presenting: true)
}

public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?
{
    return LTRTransition(presenting: false)
}
}
2
user246672

見た目はトリッキーですが、数行のコードだけで完成させます。

まず、LeftSlideViewControllerをモーダルで提示します。 .overCurrentContextにmodalPresentationStyleを指定する必要があります。

if let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LeftSlideViewController") as? LeftSlideViewController {
         vc.modalPresentationStyle = .overCurrentContext
        self.present(vc, animated: false, completion: nil)
    }

次に、LeftSlideViewControllerを開きます。

左から移動するには(CATransitionを使用)

  • LoadViewでビューを非表示にします。

    self.view.isHidden = true
    
  • 左移動遷移アニメーションをviewDidAppearのビューに追加する

    self.view.isHidden = false
    
    let transition = CATransition.init()
    transition.duration = 0.3
    transition.timingFunction = CAMediaTimingFunction.init(name: .easeInEaseOut)
    transition.type = .moveIn
    transition.subtype = .fromLeft
    
    self.view.layer.add(transition, forKey: nil)
    

左に移動するには(UIViewアニメーションを使用)

  • UIViewのアニメーションを使用してビューのフレームをアニメーション化し、アニメーションが終了したらViewControllerを閉じます

    UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseIn, animations: {
        self.view.frame = CGRect(x: self.view.frame.width * -1, y: 0, width: self.view.frame.width, height: self.view.frame.height)
    }) { (finished) in
        self.dismiss(animated: false, completion: nil)
    }
    
1
may park

UIModalTransitionStylesは4つしかありません。

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];
0
JackTurky