自定义View Controller转换动画

观察 iOS 自带的 App,你会看到当你从一个视图导航到另一个视图时总是会显示各种各样的转换动画,以“主-从”视图为例(类似的程序有Messages App或者系统设置程序),一个轻扫动作能够让详情视图呈现在主视图之上,在呈现一个新的 View Controller 时还会带有丰富的转换动画。

iOS 7 新增的自定义 View Controller 转换动画,使让开发者在 App 中发生从一个 View Controller 到另一个 View Controller 的导航时,创建自定义的动画效果。在本教程中,我们将学习这个内容。此外,我们还会学习如何通过手势来发起一个导航,也就是所谓的“交互式导航”。在开始之前,请下载本教程中用到的开始项目

开始

创建自定义转换动画的,可以分成 3 个步骤进行:

  • 指定一个类,实现 UIViewControllerAnimatedTransitioning 协议。在这个类中,我们编写执行动画的代码。这个类充当动画控制器。
  • 在呈现一个 View Controller 之前,设置这个 View Controller 的 transitioningDelegate 属性为某个对象。这个对象在呈现这个 View Controller 的过程中将被调用,用于获取转场时应该使用什么对象作为动画控制器。
  • 实现回调方法,用于返回一个你在第一歩中创建的动画控制器对象。

运行开始项目,你将看到一个列表。在导航栏上有一个 Action 按钮,点击它,它将呈现一个新的 View Controller(以 modal 方式从底部向上弹起)。我们将为这个转换动作自定义转换动画。

Custom Present Transition

实现 View Controller 呈现动画

如前面所述,首先需要创建动画控制器。新建一个 NSObject 子类 CustomPresentAnimationController,声明将遵守 UIViewControllerAnimatedTransitioning 协议:

class CustomPresentAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

UIViewControllerAnimatedTransitioning protocol has two required methods which we’ll add next. Add the following methods to the class.

UIViewControllerAnimatedTransitioning 协议有两个必须实现的方法,我们来实现它们:

func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
    return 2.5
}

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {

    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)
    let containerView = transitionContext.containerView()
    let bounds = UIScreen.mainScreen().bounds
    toViewController.view.frame = CGRectOffset(finalFrameForVC, 0, bounds.size.height)
    containerView.addSubview(toViewController.view)

    UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: .CurveLinear, animations: {
        fromViewController.view.alpha = 0.5
        toViewController.view.frame = finalFrameForVC
        }, completion: {
            finished in
            transitionContext.completeTransition(true)
            fromViewController.view.alpha = 1.0
    })
}

第一个方法用于指定动画播放的时长。对于本例,我们指定为 2.5 秒。当然在真正的 App 你可以把这个数字调小一些。

第二个方法带有一个 transitionContext 参数,通过这个对象,我们可以获取转换过程中涉及的 from 控制器(开始控制器)、to 控制器(到达控制器)、当动画完成后的 final frame (to 视图的最终位置及大小),以及 containerView——这个容器用于包含 from 控制器和 to 控制器的 UIView。

然后,我们将 to 视图放在屏幕的下方,并将 to 视图添加到 containerView。在动画块中,我们将 to 视图移动到 final frame 的位置。同时将 from 视图的 alpha 值设置为 0.5,这样,当 to 视图向上滑入的同时 from 视图淡出。执行动画块时,第一个参数调用了transitionDuration(transitionContext:)方法,用这个方法的返回值作为动画块的执行时间。当动画完成,调用完成块,我们在完成块中通知 transitionContext 动画已经完成,同时将 from 视图的 alpha 值设回 1.0。

写好动画控制器类之后,我们需要在故事板中将动画控制器分配给某个 segue。

打开 ItemsTableViewController.swift ,修改类声明如下:

class ItemsTableViewController: UITableViewController, UIViewControllerTransitioningDelegate {

UIViewController 有一个 transitionDelegate 属性,用于指定自定义转换动画。当转场到一个 View Controller 时,框架会使用这个属性进行转换。而 UIViewControllerTransitioningDelegate 属性则负责提供自定义转换对象。

打开 Main.storyboard 选择导航到 Action View Controller 的那条 segue,在属性面板将它的 Identifier 设置为 showAction。

回到 ItemsTableViewController ,添加如下代码:

let customPresentAnimationController = CustomPresentAnimationController()

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    if segue.identifier == "showAction" {
        let toViewController = segue.destinationViewController as UIViewController
        toViewController.transitioningDelegate = self
    }
}

这里我们创建了一个我们的动画控制器对象,然后在 prepareForSegue() 方法中,找到 ID 为 showAction 的 segue,设置它的 to 视图控制器的 transitioningDelegate 属性。

然后在这个类中实现 UIViewControllerTransitioningDelegate 方法。并在这些方法中返回我们的自定义动画控制器。

func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    return customPresentAnimationController
}

运行程序,你可以看到 Action 视图从屏幕底部缓缓弹起,并在停止前呈阻尼运动。

如果想看看其他效果,在 CustomPresentAnimationController.swift 中找到如下语句:

toViewController.view.frame = CGRectOffset(finalFrameForVC, 0, bounds.size.height)

修改为:

toViewController.view.frame = CGRectOffset(finalFrameForVC, 0, -bounds.size.height)

这将让 to 视图从屏幕上方向下滑入。

运行 App 效果如下:

自定义解散动画

前面我们自定义了呈现动画,但当视图解散时,仍然使用的是默认的动画效果。

UIViewControllerTransitioningDelegate 协议还允许我们指定一个动画控制器作位解散动画,就如同呈现时我们所做的一样。我们接下来就来实现它。

创建一个 NSObject 子类 CustomDismissAnimationController,修改其类声明如下:

class CustomDismissAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

添加如下方法:

func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
    return 2
}

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)
    let containerView = transitionContext.containerView()
    toViewController.view.frame = finalFrameForVC
    toViewController.view.alpha = 0.5
    containerView.addSubview(toViewController.view)
    containerView.sendSubviewToBack(toViewController.view)

    UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
        fromViewController.view.frame = CGRectInset(fromViewController.view.frame, fromViewController.view.frame.size.width / 2, fromViewController.view.frame.size.height / 2)
        toViewController.view.alpha = 1.0
    }, completion: {
        finished in
        transitionContext.completeTransition(true)
    })
}

其实这和呈现动画的实现真的很像。在 animateTransition() 方法中,我们获取 to/from 视图控制器。在这里,to 控制器变成了表格控制器。我们修改了 to 视图在动画正式开始之前的 alpha 值。然后将 to 视图添加到 containerView,并将它放到 from 视图的后面,以便它在一开始的时候不可见。

在动画块中,我们让 from 视图的大小变成 0,0,但中心位置不变。这将导致 from 视图由大变小直至消失。同时将 to 视图的 alpha 值设置为 1.0 使其可见。

在 ItemsTableViewController 中添加几个属性声明:

let customDismissAnimationController = CustomDismissAnimationController()

然后加入如下方法:

func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {

return customDismissAnimationController

}

UIViewControllerTransitioningDelegate 协议的这个方法返回一个动画控制器作为解散控制器。

运行效果如下:

动画效果不是我们所预料的。你可以看到 from 视图的白色框架确实是如预期的缩小了,但图片的尺寸根本不会改变。这是因为仅仅改变视图的 frame 并不会影响它的 subviews。我们可以用 UIView 的截屏功能解决这个问题。

UIView 截屏功能会对一个 UIView 进行截图,将它绘制在一个“轻量级”的 UIView 中。我们将在淡入淡出动画中使用截屏进行动画,而不是直接用真正的视图进行动画。

将 animateTransition() 方法代码修改为:

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)
    let containerView = transitionContext.containerView()
    toViewController.view.frame = finalFrameForVC
    toViewController.view.alpha = 0.5
    containerView.addSubview(toViewController.view)
    containerView.sendSubviewToBack(toViewController.view)

    let snapshotView = fromViewController.view.snapshotViewAfterScreenUpdates(false)
    snapshotView.frame = fromViewController.view.frame
    containerView.addSubview(snapshotView)

    fromViewController.view.removeFromSuperview()

    UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
        snapshotView.frame = CGRectInset(fromViewController.view.frame, fromViewController.view.frame.size.width / 2, fromViewController.view.frame.size.height / 2)
        toViewController.view.alpha = 1.0
    }, completion: {
        finished in
        snapshotView.removeFromSuperview()
        transitionContext.completeTransition(true)
    })
}

这里,我们创建了 from 视图的截屏,将截屏加到 containerView,然后将 from 视图从 containerView 中移除。

现在,动画效果终于正常了。

定制导航控制器转换动画

面看到,要在呈现一个模式窗口的过程中呈现自定义动画,我们需要让负责呈现的 View Controller 实现一个 Transitioning 协议。但是,为每个 View Controller 都指定一个委托对象还是太麻烦了,尤其是当我们在使用 UITabBarController 或 UINavigationController 的时候。

对于这两种控制器,有一种更简单的办法,可以使用 UITabBarControllerDelegate 或者 UINavigationControllerDelegate 协议来实现自定义转换动画。

我们来看一下自定义导航控制器转换动画的例子。

首先,创建一个动画控制器。新建一个 NSObject 子类 CustomNavigationAnimationController。修改其类声明如下:

class CustomNavigationAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

然后编写如下代码。这里我准备实现一个简单的魔方动画。这个动画控制器和前面实现的两个动画控制器类似。注意 reverse 变量,我们用这个变量来指定动画的方向,也就是说要进行的动画是主视图->从视图,抑或相反方向。

var reverse: Bool = false

func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
    return 1.5
}

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    let containerView = transitionContext.containerView()
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    let toView = toViewController.view
    let fromView = fromViewController.view
    let direction: CGFloat = reverse ? -1 : 1
    let const: CGFloat = -0.005

    toView.layer.anchorPoint = CGPointMake(direction == 1 ? 0 : 1, 0.5)
    fromView.layer.anchorPoint = CGPointMake(direction == 1 ? 1 : 0, 0.5)

    var viewFromTransform: CATransform3D = CATransform3DMakeRotation(direction * CGFloat(M_PI_2), 0.0, 1.0, 0.0)
    var viewToTransform: CATransform3D = CATransform3DMakeRotation(-direction * CGFloat(M_PI_2), 0.0, 1.0, 0.0)
    viewFromTransform.m34 = const
    viewToTransform.m34 = const

    containerView.transform = CGAffineTransformMakeTranslation(direction * containerView.frame.size.width / 2.0, 0)
    toView.layer.transform = viewToTransform
    containerView.addSubview(toView)

    UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
        containerView.transform = CGAffineTransformMakeTranslation(-direction * containerView.frame.size.width / 2.0, 0)
        fromView.layer.transform = viewFromTransform
        toView.layer.transform = CATransform3DIdentity
    }, completion: {
        finished in
        containerView.transform = CGAffineTransformIdentity
        fromView.layer.transform = CATransform3DIdentity
        toView.layer.transform = CATransform3DIdentity
        fromView.layer.anchorPoint = CGPointMake(0.5, 0.5)
        toView.layer.anchorPoint = CGPointMake(0.5, 0.5)

        if (transitionContext.transitionWasCancelled()) {
            toView.removeFromSuperview()
        } else {
            fromView.removeFromSuperview()
        }
        transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
    })
}

打开 ItemsTableViewController.swift,将类声明修改为:

class ItemsTableViewController: UITableViewController, UIViewControllerTransitioningDelegate, UINavigationControllerDelegate {

UINavigationControllerDelegate 协议负责提供动画控制器对象。

添加如下属性:

let customNavigationAnimationController = CustomNavigationAnimationController()

在 viewDidLoad 方法最后添加:

navigationController?.delegate = self

这句代码将导航控制器的 delegate 设置为 self,这样 ItemsTableViewController 就必须实现新的转换委托方法。

新增如下方法:

func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    customNavigationAnimationController.reverse = operation == .Pop
    return customNavigationAnimationController
}

这个方法会在导航控制器发生导航时调用,导航控制器会要求这个方法返回一个动画控制器实例。转换的方向根据动画的类型(Push或Pop)而定。

运行程序。点击表格单元格,效果如下:

交互式转换

我们将让上述转换变成“交互式转换”,这样用户可以用手势来进行视图控制器的转换。

iOS 有许多 App 支持这个特性。通过交互式转换,你可以从左向右滑动来替代返回按钮的功能。你还可以用小幅度的轻扫手势查看 master 视图的内容,然后中途取消转换。大幅度的轻扫手势则是进行 Pop 导航操作。

首先,需要创建一个交互式控制器。交互式控制器需要实现 UIViewControllerInteractiveTransitioning 协议。UINavigationControllerDelegate 或 Transitioning 委托在请求完一个动画控制器之后还会请求一个交互式控制器。

接下来创建交互式控制器。新建一个 UIPercentDrivenInteractiveTransition 子类,名为 CustomInteractionController。

UIPercentDrivenInteractiveTransition 类已经实现了 UIViewControllerInteractiveTransitioning 协议,因此我们的类就没有必要再声明对这个协议的实现了。

对于 UIPercentDrivenInteractiveTransition 子类,我们必须使用单独的 UIView 动画,以便动画能够被停止、返回和播放。

继续添加如下代码:

var navigationController: UINavigationController!
var shouldCompleteTransition = false
var transitionInProgress = false
var completionSeed: CGFloat {
    return 1 - percentComplete
}

func attachToViewController(viewController: UIViewController) {
    navigationController = viewController.navigationController
    setupGestureRecognizer(viewController.view)
}

private func setupGestureRecognizer(view: UIView) {
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: "handlePanGesture:"))
}

func handlePanGesture(gestureRecognizer: UIPanGestureRecognizer) {
    let viewTranslation = gestureRecognizer.translationInView(gestureRecognizer.view!.superview!)
    switch gestureRecognizer.state {
    case .Began:
        transitionInProgress = true
        navigationController.popViewControllerAnimated(true)
    case .Changed:
        var const = CGFloat(fminf(fmaxf(Float(viewTranslation.x / 200.0), 0.0), 1.0))
        shouldCompleteTransition = const > 0.5
        updateInteractiveTransition(const)
    case .Cancelled, .Ended:
        transitionInProgress = false
        if !shouldCompleteTransition || gestureRecognizer.state == .Cancelled {
            cancelInteractiveTransition()
        } else {
            finishInteractiveTransition()
        }
    default:
        println("Swift switch must be exhaustive, thus the default")
    }
}

attachToViewController方法中,引用了一个导航控制器并保存到实例变量,以便当手势发生时用于初始化 Pop 转换。然后在视图中添加了一个手势识别器,并将手势处理方法指定为 handlePanGesture()方法。手势处理方法将处理手势的每一个状态,包括:

  • 开始:将 transitionInProgress 设置为 true,然后开始进行 Pop 导航。
  • 改变:这个状态表示手势尚处于进行过程中,因此需要计算出转换的进度(百分比)。这里假设扫动距离>= 200像素视同手势100%的完成。如果小于此距离则计算手势划过的距离占200像素的百分之几,并以此作为动画完成的进度。同时我们检查用户在释放手指前,划过的距离是否超过了一半,并将判断结果保存到 shouldCompleteTransition 变量。
  • 取消/结束:将 transitionInProgress 设置为 false,同时判断 shouldCompleteTransition 变量是否为 false 或者手势已取消,如果是则取消动画,否则让动画完成。

用一个计算属性来衡量完成速度。 UIPercentDrivenInteractiveTransitio 有一个 completionSeed 属性,这个属性用于告诉框架当手势已经完成时,还剩下多少动画需要播放。当手势取消时,如果这个数值越大,则 View Controller 弹回去的速度就越快。

接下来就是使用这个交互式控制器。打开 ItemsTableViewController.swift,添加如下属性:

let customInteractionController = CustomInteractionController()

在 navigationController(_:animationControllerForOperation:fromViewController:toViewController:)方法开始部分加入:

if operation == .Push {
    customInteractionController.attachToViewController(toVC)
}

如果是 Push 动画,则调用 CustomInteractionController 的 attachToViewController() 方法,将 toViewController 传递给动画控制器。

然后添加如下方法:

func navigationController(navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
    return customInteractionController.transitionInProgress ? customInteractionController : nil
}

当框架请求一个动画控制器之时,它也会用上面的这个方法请求一个交互式控制器。在这个方法中,我们判断是否转换开始,如果是,则返回一个交互式控制器给它。

运行 App ,查看转换动画效果:

结论

我们学习了如何创建一个自定义的 View Controller 转换,以及如何创建交互式转换。通过这些特性,开发者可以在 App 中彻底控制从一个视图控制器切换到另一个视图控制器时的转换动画,并通过创建一系列独特的体验来取悦他们的用户。你可以从此下载完整的示例项目。

注意: 本教程有一个中文版本(台湾繁体)。我们还将支持更多语言。如果你想参加我们的翻译小组,请和我们联系。

时间: 2024-10-12 09:36:34

自定义View Controller转换动画的相关文章

Swift:超炫的View Controller切换动画

匿名社交应用Secret的开发者开发了一款叫做Ping的应用,用户可以他们感兴趣的话题的推送. Ping有一个很炫的东西,就是主界面和之间切换的动画做的非常的好.每次看到一个非常炫的动画,都不由得会想:“这个东西我要不要自己实现以下”.哈哈~~~ 这个教程里,你会学到如何用Swift实现这样的很酷的动画.你会学到如何使用shape layer,遮罩和使用UIViewControllerAnimnatedTransitioning协议和UIPercentDrivenInteractivetrans

Android属性动画与自定义View——实现vivo x6更新系统的动画效果

晚上好,现在是凌晨两点半,然后我还在写代码.电脑里播放着<凌晨两点半>,晚上写代码,脑子更清醒,思路更清晰. 今天聊聊属性动画和自定义View搭配使用,前面都讲到自定义View和属性动画,但是一起用的还是不多,刚巧今晚手机提示我更新系统,我看到那个更新的动画还不错,仔细的分析了一下,于是我也决定写一个,不是一模一样的,但是效果和原理是一样的. 先看看图: 这是一张静态的图,这里有三个波浪线,当下载完之后,波浪线会往上活动,一直到消失. 所以难点也是在这个波浪线上.这个波浪线类似于一个水波纹,也

View Controller容器

在 iOS 5 之前,view controller 容器是 Apple 的特权.实际上,在 view controller 编程指南中还有一段申明,指出你不应该使用它们.Apple 对 view controllers 的总的建议曾经是"一个 view controller 管理一个全屏幕的内容".这个建议后来被改为"一个 view controller 管理一个自包含的内容单元".为什么 Apple 不想让我们构建自己的 tab bar controllers

View Controller 转场

自定义转场动画 iOS 7 中最让我激动的特性之一就是提供了新的 API 来支持自定义 view contrioller 之间的转场动画.iOS 7 发布之前,我自己写过一些 view controller 之间的转场动画,这是一个比较头疼的过程,而且这种做法并不被苹果完全地支持,尤其是如果你想让这个转场动画有交互式的效果就更难了. 在继续阅读之前,我需要先声明一下:这个 API 是新近才发布的,目前还没有所谓的最佳实践.通常来说,开发者需要探索几个月才能得出关于新 API 的最佳实践.因此请将

【Android自定义View实战】之仿QQ运动步数圆弧及动画,Dylan计步中的控件StepArcView

转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/52936609[DylanAndroid的csdn博客] 在之前的Android超精准计步器开发-Dylan计步中的首页用到了一个自定义控件,和QQ运动的界面有点类似,还有动画效果,下面就来讲一下这个View是如何绘制的. 1.先看效果图 2.效果图分析 功能说明:黄色的代表用户设置的总计划锻炼步数,红色的代表用户当前所走的步数. 初步分析:完全自定义View重写onDraw(

Android_自定义view动画按钮

昨天偶偶然看见UI 给的一个交互的效果,原图如下 就是下面的loginbutton,于是大概模仿了一下, 并没有做这个UI的全部效果,有兴趣的可以完善后面展开的效果 下面是demo的button效果 这个View用到的知识点比较简单: view的坐标系知识,(大家没有不熟悉的吧) view的canvas基本API(画矩形,画扇形,) view的自定义属性(attr提供选项) 属性动画的知识(老生常谈的知识,ObjectAnimation和ValueAniamtion) 下面我们就一步步实现这个b

Android自定义View——仿vivo i管家病毒扫描动画效果

技术是永无止境的,如果真的爱技术,那就勇敢的坚持下去.我很喜欢这句话,当我在遇到问题的时候.当我觉得代码枯燥的时候,我就会问自己,到底是不是真的热爱技术,这个时候,我心里总是起着波澜,我的答案是肯定的,我深深的爱着这门技术. 今天我们继续聊聊Android的自定义View系列.先看看效果吧: 这个是我手机杀毒软件的一个动画效果,类似于雷达搜索,所以用途还是很广泛的,特别是先了解一下这里的具体逻辑和写法,对技术的进步一定很有用. 先简单的分析一下这里的元素,主要有四个圆.一个扇形.还有八条虚线.当

Android 自定义View修炼-自定义加载进度动画LoadingImageView

一.概述 本自定义View,是加载进度动画的自定义View,继承于ImageView来实现,主要实现蒙层加载进度的加载进度效果. 支持水平左右加载和垂直上下加载四个方向,同时也支持自定义蒙层进度颜色. 直接看下面的效果图吧. 二.效果图 废话不说,先来看看效果图吧~~ 三.实现原理方案 1.自定义View-XCLoadingImageView,继承ImageVIew来实现,这样就不用自己再处理drawable和测量的工作内容. 2.根据蒙层颜色创建一个蒙层bitmap,然后根据这个bitmap来

android 自定义view+属性动画实现充电进度条

近期项目中需要使用到一种类似手机电池充电进度的动画效果,以前没学属性动画的时候,是用图片+定时器的方式来完成的,最近一直在学习动画这一块,再加上复习一下自定义view的相关知识点,所以打算用属性动画和自定义view的方式来完成这个功能,将它开源出来,供有需要的人了解一下相关的内容. 本次实现的功能类似下面的效果: 接下来便详细解析一下如何完成这个功能,了解其中的原理,这样就能举一反三,实现其他类似的动画效果了. 详细代码请看大屏幕 https://github.com/crazyandcoder