我曾经使用了一种很好的方法来关闭我的模态视图控制器:
[self dismissModalViewControllerWithTransition:2];
如何实现从左到右的幻灯片转换效果,就像导航控制器在弹出视图时所做的那样。
由于这种方法是非公开方法,苹果不会接受它。我该如何在我的代码中编程实现这种动画(从左向右滑动以关闭模态视图,从右向左滑动以呈现模态视图)?
提前感谢。
我曾经使用了一种很好的方法来关闭我的模态视图控制器:
[self dismissModalViewControllerWithTransition:2];
如何实现从左到右的幻灯片转换效果,就像导航控制器在弹出视图时所做的那样。
由于这种方法是非公开方法,苹果不会接受它。我该如何在我的代码中编程实现这种动画(从左向右滑动以关闭模态视图,从右向左滑动以呈现模态视图)?
提前感谢。
我已经接受了Safecase的答案,但我想在这里发布我的最终解决方案:
1)为了以从右侧到左侧的转换方式呈现模态视图控制器,我编写了以下方法:
-(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) 以从左向右的滑动转换方式关闭模态视图:
-(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];
}
谢谢大家!
[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];
ModalService
类,它是一个预打包的灵活解决方案,可以轻松地添加到项目中,并在需要时从任何位置调用。该类将模态视图从指定方向带入当前视图之上,然后在退出时将其移动出来以显示其后面的原始视图。只需提供当前正在显示的presentingViewController
和您创建并希望显示的modalViewController
即可调用:ModalService.present(modalViewController, presenter: presentingViewController)
。
ModalService.dismiss(modalViewController)
当然,可以从modalViewController本身调用此方法,如ModalService.dismiss(self)
。请注意,解除模态视图不必从presentingViewController调用,并且不需要了解或引用原始的presentingViewController。
该类提供合理的默认值,包括将模态视图从右侧转换进入并向左侧退出。可以通过传递方向来自定义此转换方向,可为进入和退出都进行自定义:
ModalService.present(modalViewController, presenter: presentingViewController, enterFrom: .left)
并且
ModalService.dismiss(self, exitTo: .left)
.left
,.right
,.top
和.bottom
。如果需要,您也可以传递自定义的持续时间(以秒为单位):ModalService.present(modalViewController, presenter: presentingViewController, enterFrom: .left, duration: 0.5)
并且
ModalService.dismiss(self, exitTo: .left, duration: 2.0)
向 @jcdmb 致敬,他在这个问题上的 Objective C 答案是解决方案中的核心。
transitionSubtype
返回的值看起来很奇怪,但这样设置是有意义的。在做出更改之前,请先测试观察到的行为。 :)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
}
}
}
}