MotionTransitioning 8.0.0

MotionTransitioning 8.0.0

测试测试
语言语言 Obj-CApache-2.0
发布上次发布2021年4月

Jeff VerkoeyenIan GordonAdrian Secord维护。



  • Material Motion 作者团队

Motion Transitioning

轻量级的 API,用于构建 UIViewController 转换。

Build Status codecov CocoaPods Compatible Platform Docs

本库标准化了在 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

指南

  1. 架构
  2. 如何创建渐变过渡
  3. 如何自定义演示
  4. 如何自定义导航控制器过渡

架构

背景:在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()
    })
  }
}

如何自定义呈现

在需要执行以下操作时,自定义转换的呈现:

  • 添加视图,例如半透明视图,它们存在于转换的生命周期之外。
  • 改变被呈现视图控制器的目标框架。

您有两种自定义呈现的选项:

  1. 使用提供的 TransitionPresentationController API。
  2. 创建自己的 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文件。