17

我正在使用一种很好的方法来关闭我的模态视图控制器:

[self dismissModalViewControllerWithTransition:2];

这使得从左到右的滑动过渡,就像导航控制器弹出视图一样。

由于该方法是非公开方法,Apple 不会接受。如何在我的代码中编写这种动画(从左向右滑动以关闭模态视图,从右向左滑动以呈现模态视图)?

提前致谢

4

3 回答 3

42

我已经接受了 Safecase 的答案,但我想在这里发布我的最终解决方案:

1) To present a modal view controller with a from right to left transition I have written following method:

-(void) presentModalView:(UIViewController *)controller {
    CATransition *transition = [CATransition animation];
    transition.duration = 0.35;
    transition.timingFunction =
    [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    transition.type = kCATransitionMoveIn;
    transition.subtype = kCATransitionFromRight;

    // NSLog(@"%s: self.view.window=%@", _func_, self.view.window);
    UIView *containerView = self.view.window;
    [containerView.layer addAnimation:transition forKey:nil];
    [self presentModalViewController:controller animated:NO];
}

2) To dismiss a modal view with an slide transition left to right:

-(void) dismissMe {
    CATransition *transition = [CATransition animation];
    transition.duration = 0.35;
    transition.timingFunction =
    [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    transition.type = kCATransitionMoveIn;
    transition.subtype = kCATransitionFromLeft;

    // NSLog(@"%s: controller.view.window=%@", _func_, controller.view.window);
    UIView *containerView = self.view.window;
    [containerView.layer addAnimation:transition forKey:nil];

    [self dismissModalViewControllerAnimated:NO];
}

Thanks guys!

于 2012-07-10T13:10:16.870 回答
7

试试这个:

我假设您正在从视图控制器 1 中关闭视图控制器 2。在视图控制器 2 中,您正在使用它

[self  dismissModalViewControlleAnimated: NO]];

现在在第一个视图控制器中,在 viewWillAppear: 方法中添加代码

CATransition *animation = [CATransition animation];

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

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


[self.view.layer addAnimation:animation forKey:kCATransition];
于 2012-07-10T12:14:49.953 回答
1

This Swift 4 ModalService class below is a pre-packaged flexible solution that can be dropped into a project and called from anywhere it is required. This class brings the modal view in on top of the current view from the specified direction, and then moves it out to reveal the original view behind it when it exits. Given a presentingViewController that is currently being displayed and a modalViewController that you have created and wish to display, you simply call:

ModalService.present(modalViewController, presenter: presentingViewController)

Then, to dismiss, call:

ModalService.dismiss(modalViewController)

This can of course be called from the modalViewController itself as ModalService.dismiss(self). Note that dismissing does not have to be called from the presentingViewController, and does not require knowledge of or a reference to the original presentingViewController.

The class provides sensible defaults, including transitioning the modal view in from the right and out to the left. This transition direction can be customised by passing a direction, which can be customised for both entry and exit:

ModalService.present(modalViewController, presenter: presentingViewController, enterFrom: .left)

and

ModalService.dismiss(self, exitTo: .left)

This can be set as .left, .right, .top and .bottom. You can likewise pass a custom duration in seconds if you wish:

ModalService.present(modalViewController, presenter: presentingViewController, enterFrom: .left, duration: 0.5)

and

ModalService.dismiss(self, exitTo: .left, duration: 2.0)

Head nod to @jcdmb for the Objective C answer on this question which formed the kernel of the solution in this class.


Here's the full class. The values returned by the private transitionSubtype look odd but are set this way deliberately. You should test the observed behaviour before assuming these need 'correcting'. :)

import UIKit

class ModalService {

    enum presentationDirection {
        case left
        case right
        case top
        case bottom
    }

    class func present(_ modalViewController: UIViewController,
                       presenter fromViewController: UIViewController,
                       enterFrom direction: presentationDirection = .right,
                       duration: CFTimeInterval = 0.3) {
        let transition = CATransition()
        transition.duration = duration
        transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        transition.type = kCATransitionMoveIn
        transition.subtype = ModalService.transitionSubtype(for: direction)
        let containerView: UIView? = fromViewController.view.window
        containerView?.layer.add(transition, forKey: nil)
        fromViewController.present(modalViewController, animated: false)
    }

    class func dismiss(_ modalViewController: UIViewController,
                       exitTo direction: presentationDirection = .right,
                       duration: CFTimeInterval = 0.3) {
        let transition = CATransition()
        transition.duration = duration
        transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        transition.type = kCATransitionReveal
        transition.subtype = ModalService.transitionSubtype(for: direction, forExit: true)
        if let layer = modalViewController.view?.window?.layer {
            layer.add(transition, forKey: nil)
        }
        modalViewController.dismiss(animated: false)
    }

    private class func transitionSubtype(for direction: presentationDirection, forExit: Bool = false) -> String {
        if (forExit == false) {
            switch direction {
            case .left:
                return kCATransitionFromLeft
            case .right:
                return kCATransitionFromRight
            case .top:
                return kCATransitionFromBottom
            case .bottom:
                return kCATransitionFromTop
            }
        } else {
            switch direction {
            case .left:
                return kCATransitionFromRight
            case .right:
                return kCATransitionFromLeft
            case .top:
                return kCATransitionFromTop
            case .bottom:
                return kCATransitionFromBottom
            }
        }
    }
}
于 2017-10-04T07:23:00.557 回答