我正在使用presentViewController来呈现新屏幕
let dashboardWorkout = DashboardWorkoutViewController()
presentViewController(dashboardWorkout, animated: true, completion: nil)
这显示了从下到上的新屏幕,但我希望它在不使用UINavigationController
的情况下从右到左呈现。
我使用Xib而不是故事板,所以我该怎么做?
答案 0 :(得分:127)
如果您使用的是xib
或storyboard
,则无关紧要。通常,当您将视图控制器推送到提交者的UINavigiationController
时,会使用从右到左的转换。
<强>更新强>
添加了计时功能kCAMediaTimingFunctionEaseInEaseOut
Swift 3&amp; 4.2 强>
let transition = CATransition()
transition.duration = 0.5
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromRight
transition.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeInEaseOut)
view.window!.layer.add(transition, forKey: kCATransition)
present(dashboardWorkout, animated: false, completion: nil)
的 ObjC 强>
CATransition *transition = [[CATransition alloc] init];
transition.duration = 0.5;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[transition setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[self.view.window.layer addAnimation:transition forKey:kCATransition];
[self presentViewController:dashboardWorkout animated:false completion:nil];
Swift 2.x
let transition = CATransition()
transition.duration = 0.5
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromRight
transition.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut)
view.window!.layer.addAnimation(transition, forKey: kCATransition)
presentViewController(dashboardWorkout, animated: false, completion: nil)
似乎animated
方法中的presentViewController
参数在这种自定义转换的情况下并不重要。它可以是任何值,true
或false
。
答案 1 :(得分:40)
完整的现在/解雇代码,Swift 3
extension UIViewController {
func presentDetail(_ viewControllerToPresent: UIViewController) {
let transition = CATransition()
transition.duration = 0.25
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromRight
self.view.window!.layer.add(transition, forKey: kCATransition)
present(viewControllerToPresent, animated: false)
}
func dismissDetail() {
let transition = CATransition()
transition.duration = 0.25
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromLeft
self.view.window!.layer.add(transition, forKey: kCATransition)
dismiss(animated: false)
}
}
答案 2 :(得分:16)
阅读所有答案,但无法找到正确的解决方案。正确的方法是为呈现的VC委托制作自定义UIViewControllerAnimatedTransitioning。
因此,它假定采取更多步骤,但结果更具可定制性,并且避免了一些副作用,例如从视图移动到现有视图。
所以,假设你有一些ViewController,并且有一种方法来呈现
var presentTransition: UIViewControllerAnimatedTransitioning?
var dismissTransition: UIViewControllerAnimatedTransitioning?
func showSettings(animated: Bool) {
let vc = ... create new vc to present
presentTransition = RightToLeftTransition()
dismissTransition = LeftToRightTransition()
vc.modalPresentationStyle = .custom
vc.transitioningDelegate = self
present(vc, animated: true, completion: { [weak self] in
self?.presentTransition = nil
})
}
presentTransition
和dismissTransition
用于为视图控制器设置动画。
因此,您将ViewController采用到UIViewControllerTransitioningDelegate
:
extension ViewController: UIViewControllerTransitioningDelegate {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return presentTransition
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return dismissTransition
}
}
所以最后一步是创建自定义转换:
class RightToLeftTransition: NSObject, UIViewControllerAnimatedTransitioning {
let duration: TimeInterval = 0.25
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return duration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let container = transitionContext.containerView
let toView = transitionContext.view(forKey: .to)!
container.addSubview(toView)
toView.frame.origin = CGPoint(x: toView.frame.width, y: 0)
UIView.animate(withDuration: duration, delay: 0, options: .curveEaseOut, animations: {
toView.frame.origin = CGPoint(x: 0, y: 0)
}, completion: { _ in
transitionContext.completeTransition(true)
})
}
}
class LeftToRightTransition: NSObject, UIViewControllerAnimatedTransitioning {
let duration: TimeInterval = 0.25
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return duration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let container = transitionContext.containerView
let fromView = transitionContext.view(forKey: .from)!
container.addSubview(fromView)
fromView.frame.origin = .zero
UIView.animate(withDuration: duration, delay: 0, options: .curveEaseIn, animations: {
fromView.frame.origin = CGPoint(x: fromView.frame.width, y: 0)
}, completion: { _ in
fromView.removeFromSuperview()
transitionContext.completeTransition(true)
})
}
}
在该代码视图控制器中显示当前上下文,您可以从该点进行自定义。您也可以看到自定义UIPresentationController
也很有用(使用UIViewControllerTransitioningDelegate
传递)
答案 3 :(得分:13)
您也可以使用自定义segue。
Swift 3
class SegueFromRight: UIStoryboardSegue
{
override func perform()
{
let src = self.source
let dst = self.destination
src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
dst.view.transform = CGAffineTransform(translationX: src.view.frame.size.width, y: 0)
UIView.animate(withDuration: 0.25,
delay: 0.0,
options: UIViewAnimationOptions.curveEaseInOut,
animations: {
dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
},
completion: { finished in
src.present(dst, animated: false, completion: nil)
}
)
}
}
答案 4 :(得分:6)
试试这个,
let animation = CATransition()
animation.duration = 0.5
animation.type = kCATransitionPush
animation.subtype = kCATransitionFromRight
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
vc.view.layer.addAnimation(animation, forKey: "SwitchToView")
self.presentViewController(vc, animated: false, completion: nil)
此处vc
是viewcontroller,在您的情况下为dashboardWorkout
。
答案 5 :(得分:4)
class AA: UIViewController
func goToBB {
let bb = .. instantiateViewcontroller, storyboard etc .. as! AlreadyOnboardLogin
let tr = CATransition()
tr.duration = 0.25
tr.type = kCATransitionMoveIn // use "MoveIn" here
tr.subtype = kCATransitionFromRight
view.window!.layer.add(tr, forKey: kCATransition)
present(bb, animated: false)
bb.delegate, etc = set any other needed values
}
然后......
func dismissingBB() {
let tr = CATransition()
tr.duration = 0.25
tr.type = kCATransitionReveal // use "Reveal" here
tr.subtype = kCATransitionFromLeft
view.window!.layer.add(tr, forKey: kCATransition)
dismiss(self) .. or dismiss(bb), or whatever
}
CATransition
并非真正为这项工作做好准备。
请注意,你会得到令人讨厌的交叉渐变为黑色,但遗憾的是这会破坏效果。
许多开发者(像我一样)真的不喜欢使用NavigationController
。通常情况下,您可以更灵活地以特别的方式呈现,特别是对于不寻常和复杂的应用程序。但是,添加&#34;并不困难。导航控制器。
只需在故事板上,转到条目VC并点击&#34;嵌入 - &gt;在导航控制器&#34;。真的是这样的。或者,
didFinishLaunchingWithOptions
如果您愿意,可以轻松构建导航控制器
您甚至不需要将变量保留在任何位置,因为.navigationController
始终可用作属性 - 很容易。
真的,一旦你有了一个navigationController,在屏幕之间进行转换是微不足道的,
let nextScreen = instantiateViewController etc as! NextScreen
navigationController?
.pushViewController(nextScreen, animated: true)
你可以pop
。
(旧的滑板以较低的速度滑落,因为新的滑动。)
一般而且令人惊讶的是,您通常必须努力进行完全自定义转换。
即使您只想要最简单,最常见的移动/移动过渡,您也必须进行完全自定义过渡。
幸运的是,要做到这一点,在此质量保证上有一些剪切和粘贴样板代码...... https://stackoverflow.com/a/48081504/294884。 新年快乐2018年!
答案 6 :(得分:1)
试试这个。
let transition: CATransition = CATransition()
transition.duration = 0.3
transition.type = kCATransitionReveal
transition.subtype = kCATransitionFromLeft
self.view.window!.layer.addAnimation(transition, forKey: nil)
self.dismissViewControllerAnimated(false, completion: nil)
答案 7 :(得分:0)
使用Swift
在iOS中从右到左显示视图控制器func FrkTransition()
{
let transition = CATransition()
transition.duration = 2
transition.type = kCATransitionPush
transitioningLayer.add(transition,forKey: "transition")
// Transition to "blue" state
transitioningLayer.backgroundColor = UIColor.blue.cgColor
transitioningLayer.string = "Blue"
}
参与: [https://developer.apple.com/documentation/quartzcore/catransition][1]
答案 8 :(得分:0)
let transition = CATransition()
transition.duration = 0.25
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromLeft
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
tabBarController?.view.layer.add(transition, forKey: kCATransition)
self.navigationController?.popToRootViewController(animated: true)
答案 9 :(得分:0)
导入UIKit并为UIViewController创建一个扩展:
extension UIViewController {
func transitionVc(vc: UIViewController, duration: CFTimeInterval, type: CATransitionSubtype) {
let customVcTransition = vc
let transition = CATransition()
transition.duration = duration
transition.type = CATransitionType.push
transition.subtype = type
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
view.window!.layer.add(transition, forKey: kCATransition)
present(customVcTransition, animated: false, completion: nil)
}}
简单通话后:
let vC = YourViewController()
transitionVc(vc: vC, duration: 0.5, type: .fromRight)
从左到右:
let vC = YourViewController()
transitionVc(vc: vC, duration: 0.5, type: .fromleft)
您可以使用所需的持续时间更改持续时间...
答案 10 :(得分:0)
// Never Easy than this before :)
// you just need to add a Static function for navigation transition
// This Code is recommended for the view controller.
public class CustomNavigation: UIViewController {
public override func loadView() {
super.loadView();
}
public override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true);
}
public static func segueNavToLeft(view: UIView) {
let transition = CATransition()
transition.duration = 0.3
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromLeft
transition.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeInEaseOut)
view.window!.layer.add(transition, forKey: kCATransition)
}
public static func segueNavToRight(view: UIView) {
let transition = CATransition()
transition.duration = 0.3
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromRight
transition.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeInEaseOut)
view.window!.layer.add(transition, forKey: kCATransition)
}
}
// simply call in your viewcontroller:
func moveToRight() {
CustomNavigation.segueNavToRight(view: view)
let controller = self.storyboard?.instantiateViewController(withIdentifier: "id") as! YourViewController
let navigationController = UINavigationController(rootViewController: YourViewController)
navigationController.modalPresentationStyle = .fullScreen
self.present(navigationController, animated: false, completion: nil)
}
func moveToLeft() {
CustomNavigation.segueNavToLeft(view: view)
self.dismiss(animated: true, completion: nil)
}
答案 11 :(得分:0)
class RightToLeftPresentationController: UIPresentationController {
lazy var blackView: UIView = {
let view = UIView()
view.frame = self.containerView?.bounds ?? .zero
view.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.5)
return view
}()
// MARK:- Presentation
override func presentationTransitionWillBegin() {
self.containerView?.addSubview(blackView)
self.presentingViewController.transitionCoordinator?
.animate(alongsideTransition: { _ in
self.blackView.alpha = 0.5
}, completion: nil)
}
// MARK:- Dismiss
override func dismissalTransitionWillBegin() {
UIView.animate(withDuration: 0.25) {
self.blackView.alpha = 0
}
}
override func dismissalTransitionDidEnd(_ completed: Bool) {
if completed {
blackView.removeFromSuperview()
}
}
}
class RightToLeftPresentationSegue: UIStoryboardSegue {
override func perform() {
destination.modalPresentationStyle = .custom
destination.transitioningDelegate = self
source.present(destination, animated: true)
}
}
extension RightToLeftPresentationSegue: UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
let controller = RightToLeftPresentationController(presentedViewController: presented, presenting: presenting)
presented.transitioningDelegate = controller
return controller
}
}
extension RightToLeftPresentationController: UIViewControllerTransitioningDelegate {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return RightToLeftTransition()
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return LeftToRightTransition()
}
}
class RightToLeftTransition: NSObject, UIViewControllerAnimatedTransitioning {
let duration: TimeInterval = 0.25
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return duration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let container = transitionContext.containerView
let toView = transitionContext.view(forKey: .to)!
container.addSubview(toView)
toView.frame.origin = CGPoint(x: toView.frame.width, y: 0)
UIView.animate(withDuration: duration, delay: 0, options: .curveEaseOut, animations: {
toView.frame.origin = CGPoint(x: 0, y: 0)
}, completion: { _ in
transitionContext.completeTransition(true)
})
}
}
class LeftToRightTransition: NSObject, UIViewControllerAnimatedTransitioning {
let duration: TimeInterval = 0.25
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return duration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let container = transitionContext.containerView
let fromView = transitionContext.view(forKey: .from)!
container.addSubview(fromView)
fromView.frame.origin = .zero
UIView.animate(withDuration: duration, delay: 0, options: .curveEaseIn, animations: {
fromView.frame.origin = CGPoint(x: fromView.frame.width, y: 0)
}, completion: { _ in
fromView.removeFromSuperview()
transitionContext.completeTransition(true)
})
}
}
答案 12 :(得分:-1)
如果您想要保留Apple的经典动画,我有一个更好的解决方案对我有用,而不会看到您使用CATransition()看到的“黑色”转换。只需使用popToViewController方法。
您可以在
中查找所需的viewControllerself.navigationController.viewControllers // Array of VC that contains all VC of current stack
您可以通过搜索它的restorationIdentifier来查找所需的viewController。
小心:例如,如果您正在浏览3个视图控制器,当到达最后一个时,您想要弹出第一个视图控制器。在这种情况下,您将失去对有效SECOND视图控制器的引用,因为popToViewController已覆盖它。顺便说一下,有一个解决方案:你可以在popToViewcontroller之前轻松保存,以后你需要VC。它非常适合我。
答案 13 :(得分:-3)
这对我有用:
self.navigationController?.pushViewController(controller, animated: true)