Motion Transitioning
轻量级的 API,用于构建 UIViewController 转换。
本库标准化了在 iOS 上构建转换的方式,因此您只需一行代码即可选择要使用的自定义转换。
let viewController = MyViewController()
viewController.mdm_transitionController.transition = CustomTransition()
present(viewController, animated: true)
MyViewController *viewController = [[MyViewController alloc] init];
viewController.mdm_transitionController.transition = [[CustomTransition alloc] init];
[self presentViewController:viewController animated:true completion:nil];
使用本库创建转换的最简单方法是创建一个符合 Transition
协议的类。
final class CustomTransition: NSObject, Transition {
func start(with context: TransitionContext) {
CATransaction.begin()
CATransaction.setCompletionBlock {
context.transitionDidEnd()
}
// Add animations...
CATransaction.commit()
}
}
@interface CustomTransition: NSObject <MDMTransition>
@end
@implementation CustomTransition
- (void)startWithContext:(id<MDMTransitionContext>)context {
[CATransaction begin];
[CATransaction setCompletionBlock:^{
[context transitionDidEnd];
}];
// Add animations...
[CATransaction commit];
}
@end
安装
使用 CocoaPods 进行安装
CocoaPods 是 Objective-C 和 Swift 库的依赖管理器。CocoaPods 自动化使用第三方库的过程。有关更多信息,请参阅 入门指南。您可以使用以下命令安装它。
gem install cocoapods
将 MotionTransitioning
添加到您的 Podfile
文件中
pod 'MotionTransitioning'
然后运行以下命令
pod install
用法
导入框架
@import MotionTransitioning;
您现在可以访问所有API。
示例应用/单元测试
运行以下命令,检查本地仓库副本以通过目录应用程序访问
git clone https://github.com/material-motion/transitioning-objc.git
cd transitioning-objc
pod install
open MotionTransitioning.xcworkspace
指南
架构
背景:在iOS中,通过在视图控制器上设置
transitioningDelegate
来自定义转场。当视图控制器展示时,UIKit 会向转场代理请求数字、交互和展示控制器。这些控制器随后预期实现转场的运动。
MotionTransitioning在这些协议之上提供了一个薄层,具有以下优势
- 每个视图控制器都有自己的 转场控制器。这鼓励根据上下文选择转场。
- 转场以 向前/向后 的方式表达,而不是从/到。展示时我们向前移动。消失时我们向后移动。这允许转场代码用更少的逻辑条件分支来编写。
- 转场对象可以通过遵守
TransitionWith*
协议的族来自定义其行为。
如何创建渐变过渡
我们将创建一个新的渐变过渡,以便下面的代码行可以定制我们的视图控制器的展示和消失
let viewController = MyViewController()
viewController.mdm_transitionController.transition = FadeTransition()
present(viewController, animated: true)
步骤 1: 定义一种新的转换类型
转换是一个符合 Transition
协议的 NSObject
子类。
您需要实现的方法只有一个,即 start(with context:)
。此方法在关联的视图控制器被呈现或消失时被调用。
final class FadeTransition: NSObject, Transition {
func start(with context: TransitionContext) {
}
}
步骤 2: 在所有动画完成后调用完成处理程序
每个转换都提供了一种转换上下文。转换上下文必须告知转换的运动何时完成,以便上下文随后可以通知 UIKit 视图控制器转换的完成。
如果使用显式的 Core Animation 动画
final class FadeTransition: NSObject, Transition {
func start(with context: TransitionContext) {
CATransaction.begin()
CATransaction.setCompletionBlock {
context.transitionDidEnd()
}
// Your motion...
CATransaction.commit()
}
}
如果使用隐式 UIView 动画
final class FadeTransition: NSObject, Transition {
func start(with context: TransitionContext) {
UIView.animate(withDuration: context.duration, animations: {
// Your motion...
}, completion: { didComplete in
context.transitionDidEnd()
})
}
}
步骤 3: 实现动画
基本的框架已经建立,现在您可以实现动画。为了简单起见,我们将使用隐式的 UIView 动画来构建我们的动画,但您可以自由使用您喜欢的任何动画系统。
final class FadeTransition: NSObject, Transition {
func start(with context: TransitionContext) {
// This is a fairly rudimentary way to calculate the values on either side of the transition.
// You may want to try different patterns until you find one that you prefer.
// Also consider trying the MotionAnimator library provided by the Material Motion team:
// https://github.com/material-motion/motion-animator-objc
let backOpacity = 0
let foreOpacity = 1
let initialOpacity = context.direction == .forward ? backOpacity : foreOpacity
let finalOpacity = context.direction == .forward ? foreOpacity : backOpacity
context.foreViewController.view.alpha = initialOpacity
UIView.animate(withDuration: context.duration, animations: {
context.foreViewController.view.alpha = finalOpacity
}, completion: { didComplete in
context.transitionDidEnd()
})
}
}
如何自定义呈现
在需要执行以下操作时,自定义转换的呈现:
- 添加视图,例如半透明视图,它们存在于转换的生命周期之外。
- 改变被呈现视图控制器的目标框架。
您有两种自定义呈现的选项:
- 使用提供的
TransitionPresentationController
API。 - 创建自己的
UIPresentationController
子类。
选项 2:子类化 UIPresentationController
首先定义一个新的演示控制器类型
final class MyPresentationController: UIPresentationController {
}
为了让您的过渡类型合规,必须遵守 TransitionWithPresentation
以便自定义演示。请从必需的方法返回您的自定义演示控制器类,确保返回 .custom
演示样式,否则 UIKit 不会使用您的演示控制器。
extension VerticalSheetTransition: TransitionWithPresentation {
func defaultModalPresentationStyle() -> UIModalPresentationStyle {
return .custom
}
func presentationController(forPresented presented: UIViewController,
presenting: UIViewController,
source: UIViewController?) -> UIPresentationController? {
return MyPresentationController(presentedViewController: presented, presenting: presenting)
}
}
如果您的演示控制器需要动画,您可以遵守 Transition
协议以便在每次过渡开始时接收一次 start
调用。演示控制器的 start
将在过渡的 start
之前被调用。
注意:就像您的过渡一样,最终您的演示控制器必须调用其上下文上的
transitionDidEnd
,否则您的过渡不会完成。这是因为过渡控制器等待所有关联的过渡都完成后,才会通知 UIKit 视图控制器过渡已完成。
extension MyPresentationController: Transition {
func start(with context: TransitionContext) {
// Your motion...
}
}
如何自定义导航控制器过渡效果
UINavigationController
忽略推入或弹出堆栈的任何视图控制器的 transitioningDelegate
属性,而是依赖于其代理实例来定制任何过渡。这意味着我们的 transitionController
将被导航控制器忽略。
要使用 transitionController
定制单个的推/.pop 过渡,您可以利用 TransitionNavigationControllerDelegate
单例类。如果您将共享代理分配给您的导航控制器的代理,您的导航控制器将会尊重您的单个视图控制器 transitionController
中定义的动画和交互设置。
navigationController.delegate = TransitionNavigationControllerDelegate.sharedDelegate()
// Subsequent pushes and pops will honor the pushed/popped view controller's
// transitionController settings as though the view controllers were being
// presented/dismissed.
贡献
我们欢迎贡献!
查看我们的 即将到来的里程碑。
了解更多关于 我们的团队、我们的社区 和我们的 贡献者必修内容。
授权
基于Apache 2.0许可。详情请见LICENSE文件。