GTMotionTransitioning 0.0.1

GTMotionTransitioning 0.0.1

liuxc 维护。



  • liuxc123

GTMotionTransitioning

用于创建 UIViewController 过渡的轻量级 API。

该库将 iOS 上创建过渡的方式标准化,您可以使用一行代码轻松选择您想要使用的自定义过渡。

let viewController = MyViewController()
viewController.gtm_transitionController.transition = CustomTransition()
present(viewController, animated: true)
MyViewController *viewController = [[MyViewController alloc] init];
viewController.gtm_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 <GTMTransition>
@end

@implementation CustomTransition

- (void)startWithContext:(id<GTMTransitionContext>)context {
  [CATransaction begin];
  [CATransaction setCompletionBlock:^{
    [context transitionDidEnd];
  }];

  // Add animations...

  [CATransaction commit];
}

@end

安装

使用 CocoaPods 安装

CocoaPods 是 Objective-C 和 Swift 库的依赖管理器。CocoaPods 自动化在项目中使用第三方库的过程。有关更多信息,请参阅入门指南。您可以使用以下命令安装它:

gem install cocoapods

GTMotionTransitioning 添加到您的 Podfile

pod 'GTMotionTransitioning'

然后运行以下命令

pod install

用法

导入框架

@import GTMotionTransitioning;

您现在将可以访问所有 API。

示例 apps/单元测试

检查本地仓库的副本以通过运行以下命令访问“目录”应用程序

git clone https://github.com/material-motion/transitioning-objc.git
cd transitioning-objc
pod install
open GTMotionTransitioning.xcworkspace

指南

  1. 架构
  2. 如何创建淡入淡出转换
  3. 如何自定义演示
  4. 如何自定义导航控制器转换

架构

背景:在 iOS 中,通过在视图控制器上设置“transitioningDelegate”来自定义转换。当一个视图控制器被展示时,UIKit 会请求转换委托的一个动画、交互和展示控制器。然后预计这些控制器将实现转换的运动。

MotionTransitioning通过以下优点提供在这些协议之上的一个薄层

  • 每个视图控制器都有自己的转换控制器。这鼓励根据上下文选择转换。
  • 转换是以前向/后向来表示的,而不是从/到。当我们展示时,我们正在向前移动。当我们取消展示时,我们正在向后移动。这使得转换代码的逻辑分支更少。
  • 转换对象可以通过符合一系列TransitionWith*协议来自定义其行为。

如何创建淡入淡出转换

我们将创建一个新的淡入淡出转换,以便以下代码行可以自定义我们的视图控制器的展示和取消展示

let viewController = MyViewController()
viewController.gtm_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自定义单独的推入/弹出过渡,您可以使用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.

作者

liuxc123, [email protected]

许可

GTMotionTransitioning可在MIT许可下使用。有关更多信息,请参阅LICENSE文件。