图片来自网络
与
iOS
相比,在macOS
中,控制器的转场情景相对要简洁一些,没有iOS
中导航控制器的Push
和Pop
动画以及边缘返回手势, 保留下的Present
方式,倒是提供了特有的切换方式
, 可以供我们使用出许多效果.关于
NSViewController
基础细节,有兴趣的同学可以参考我的Mac开发基础教程这个系列的教程,友情提示: 自学能力好的同学可以参考github中的课程代码.
另外一门macOS 应用开发进阶课程,供有项目经验
或对组件化
感兴趣的同学参考.
在macOS 10.10
之后,关于NSViewController
,苹果公司专门在一个extension
中提供了四个方法用来处理控制器之间的关系以及切换转场处理.
1. 内嵌在同一个窗口中形式弹出新的ViewController
open func presentViewControllerAsSheet(_ viewController: NSViewController)
2. 新窗口的形式弹出新的ViewController
open func presentViewControllerAsModalWindow(_ viewController: NSViewController)
3. Popover的形式弹出新的ViewController
open func presentViewController(_ viewController: NSViewController, asPopoverRelativeTo positioningRect: NSRect, of positioningView: NSView, preferredEdge: NSRectEdge, behavior: NSPopover.Behavior)
4. 从fromViewController转换到toViewController
open func transition(from fromViewController: NSViewController, to toViewController: NSViewController, options: NSViewController.TransitionOptions = [], completionHandler completion: (() -> Swift.Void)? = nil)
在上面的系统提供的
NSViewController
四个方法中,可以分为present
和transition
两种方式:
presentViewController(NSViewController, animator: Animator)
这个方法来完成展示的,并提供一个遵守NSViewControllerPresentationAnimator
协议的animator
控制整个动画过程.
<如果希望实现自定义的Present转场效果,可以通过自定义animator方式后面会讲到具体实现步骤
>Contain View
, 通过addSubView
和 removeSubView
的方式实现两个控制器之间的动画切换展示,系统提供了下面8中过渡动画方式: @available(OSX 10.10, *)
public struct TransitionOptions : OptionSet {
public static var crossfade: NSViewController.TransitionOptions { get }
public static var slideUp: NSViewController.TransitionOptions { get }
public static var slideDown: NSViewController.TransitionOptions { get }
public static var slideLeft: NSViewController.TransitionOptions { get }
public static var slideRight: NSViewController.TransitionOptions { get }
public static var slideForward: NSViewController.TransitionOptions { get }
public static var slideBackward: NSViewController.TransitionOptions { get }
public static var allowUserInteraction: NSViewController.TransitionOptions { get }
}
crossfade效果
slideUp/slideDown 效果
slideLeft/slideRight (slideForward/slideBackward ) 效果
allowUserInteraction 效果
在进行
transition
时,所有需要切换的child ViewController
必须是同一个super ViewController
,否则会抛出异常错误.
transition
方法仅支持有父子关系
的控制器结构.transition
由父控制器super ViewController
进行调用.transition
仅在子控制器child ViewController
之间进行切换.transition
方法中,fromViewcontroller
的视图必须有superView
,否则抛出异常.构建UI界面
class ViewController: NSViewController {
1. 从Storyboard中的CustomView 连线的控件属性,用来作为容器视图,显示每个ChildViewController的内容
@IBOutlet weak var containView: MYContainView!
override func viewDidLoad() {
super.viewDidLoad()
2. 添加需要切换的子控制器: RedController 和BlueController 为自定义的两个控制器,仅显示不同的视图颜色.
addChildViewController(RedController())
addChildViewController(BlueController())
3. 需要将第一个ChildViewController的view添加到容器视图中;
containView.addSubview(childViewControllers[0].view)
4. 设置容器视图的颜色
containView.layer?.backgroundColor = NSColor.orange.cgColor
}
5. 点击下一个按钮, 从RedController 切换到BlueController
@IBAction func clickBtn(_ sender: Any) {
transition(from: childViewControllers[0], to: childViewControllers[1], options: .slideLeft, completionHandler: nil)
}
6. 点击上一个按钮, 从BlueController 切换到RedController
@IBAction func clickUpButton(_ sender: Any) {
transition(from: childViewControllers[1], to: childViewControllers[0], options: .slideRight, completionHandler: nil)
}
}
6. 修改4,5 步骤中的option 参数,可以实现不同的transition 效果.
AsSheet
@IBAction func presentTest(_ sender: Any) {
let greenVC = GreenController()
1. 以AsSheet方式弹出控制器
presentViewControllerAsModalWindow(greenVC)
}
AsModalWindow
let greenVC = GreenController()
1. 以Popover方式弹出控制器
presentViewController(greenVC, asPopoverRelativeTo: sender.bounds, of: sender, preferredEdge: NSRectEdge.maxX, behavior: NSPopover.Behavior.transient)
Jul-28-2018 20-56-14.gif
NSViewControllerPresentationAnimator
协议的对象NSViewControllerPresentationAnimator
的两个方法public protocol NSViewControllerPresentationAnimator : NSObjectProtocol {
1. present 动画时,执行这个方法,因此在这个方法中实现自定义的动画效果
public func animatePresentation(of viewController: NSViewController, from fromViewController: NSViewController)
2. dismiss动画时,执行这个方法 ,在这个方法中可以实在自定义的动画效果
public func animateDismissal(of viewController: NSViewController, from fromViewController: NSViewController)
}
presentViewController(ViewController, animator: )
class PresentAnimator: NSObject {
}
// MARK: NSViewControllerPresentationAnimator
extension PresentAnimator: NSViewControllerPresentationAnimator{
func animatePresentation(of viewController: NSViewController, from fromViewController: NSViewController) {
// 这里实现present的动画效果
/**viewController: 将要被present出来的视图控制器, fromViewcontroller --> presented动作 ---> viewController */
1. 获取容器view
let containerView = fromViewController.view
2. 计算最终显示的frame
let finalFrame = NSInsetRect(containerView.bounds, 50, 50)
3. 需要显示的view
let modalView = viewController.view
4. 设置将要显示视图的初始frame
modalView.frame = finalFrame
modalView.setFrameOrigin(NSMakePoint(finalFrame.origin.x, finalFrame.origin.y - 200))
5 .添加视图到容器视图中
containerView.addSubview(modalView)
6. 执行动画效果
NSAnimationContext.runAnimationGroup({ (animationContext) in
animationContext.duration = 0.5
modalView.animator().frame = finalFrame
}, completionHandler: nil)
}
func animateDismissal(of viewController: NSViewController, from fromViewController: NSViewController) {
// 这里实现dismiss时的动画效果
1. 获取开始动画的frame
let startFrame = viewController.view.frame
2. 执行动画
NSAnimationContext.runAnimationGroup({ (animationContext) in
animationContext.duration = 0.5
viewController.view.animator().setFrameOrigin(NSMakePoint(startFrame.origin.x, startFrame.origin.y - fromViewController.view.bounds.size.height - 100))
}) {
3. 动画完成后,移除子视图
viewController.view.removeFromSuperview()
}
}
}
自定义present 动画效果
macOS
中,控制器的转场切换无论是presentViewController
方式或者transition
方式,本质上都是将要显示的控制器视图View
,通过addSubView
方法添加到容器视图中展示.transition
的系统样式基本都可以满足使用.present
动画时,需要注意事件穿透
问题:
控制器视图(Controller View)
是通过addSubView
方式添加到容器视图中,因此在控制器视图(Controller View)
上进行点击操作,可能会触发容器视图中控件(比如按钮)的方法背景视图(自定义的NSView, 重写mouseDown方法即可)
,通过背景视图屏蔽鼠标操作,防止事件穿透到容器视图中扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有