iOS UIView动画实践(三):Transition Animation

寵の児 提交于 2019-11-30 12:32:26

前言

在上两篇文章中向大家介绍了如何创建基于动画属性的视图动画,比如位置、透明度等。但是大家有没有想过添加或删除一个视图时怎样添加相应的动画呢?

当然我们可以用第一篇文章中对用户名、密码输入框的处理办法,但是还有更好的办法处理这种状况。那就是在这篇文章中将向大家介绍的过渡转变(Transition)动画。

过渡转变动画是Apple预定义的动画集,它没有更改视图某属性起始值和终止值的概念,而只需要你设定不同的动画选项即可。

添加新视图

在进行示例之前,大家需要注意一点过渡转变动画与动画属性动画的不同之处。我们在创建动画属性动画时只需要在animations闭包中添加对视图动画属性修改的代码即可,它没有作用域或作用视图的概念。而在过渡转变动画中有作用视图的概念,也就是说我们调用过渡转变动画方法时需要指定一个作用视图。

明确这点不同之后,我们对作用视图再作进一步的说明。过渡转变动画中的作用视图并不是我们的目标视图,而是目标视图的容器视图,那么大家不难想象,如果该容器视图中有多个子视图,那么这些子视图都会有过渡转变动画效果。下面用示例像大家说明。

先看看一个简单的视图结构:

 

很明显,我们添加了一个视图作为容器视图,并且尺寸等于屏幕尺寸。在ViewController.swift中有该容器视图的Outlet以及一个图片视图:

[cpp] view plaincopy

  1. @IBOutlet weak var containerView: UIView!  

  2. let ipadView = UIImageView(frame: CGRectMake(100, 100, 200, 151.5))  

viewDidLoad()方法中给ipadView指定图片:

[cpp] view plaincopy

  1. ipadView.image = UIImage(named: "ipad")  

然后在viewDidAppear()方法中添加如下代码:

[cpp] view plaincopy

  1. UIView.transitionWithView(self.containerView, duration: 1.5, options: .TransitionFlipFromBottom, animations: {  

  2.     self.containerView.addSubview(self.ipadView)  

  3. }, completion: nil)  

上述代码就是我们今天的主角,过渡转变方法之一,它同样是UIView的类方法,共有五个参数:

  • view:第一个参数,也就是作用视图,一般都是容器视图。

  • duration:动画持续时间。

  • options:过渡转变动画选项,由它来确定过渡转变的具体展现形式。

  • animations:动画闭包。

  • completion:动画结束后执行该闭包中的代码。

除了第一个参数,其他四个参数大家应该都不会陌生。这段代码用文字解释出来就是将容器视图(containerView)添加子视图(ipadView)的过程使用.TransitionFlipFromBottom类型的过渡转变动画展示出来,持续时间为1.5秒。编译运行看看效果:

                                        

我们再来添加一个子视图(该子视图的初始化代码不再累赘):

[cpp] view plaincopy

  1. UIView.transitionWithView(self.containerView, duration: 1.5, options: .TransitionFlipFromBottom, animations: {  

  2.     self.containerView.addSubview(self.ipadView)  

  3.     self.containerView.addSubview(self.iphoneView)  

  4. }, completion: nil)  

编译运行看看效果:

                                        

大家可以看到这两个子视图都依托与它们的容器视图进行了过渡转变动画。下面的列表是所有过渡转变动画的动画选项,大家可以在你们自己的项目中逐个实验:

  • .TransitionFlipFromLeft

  • .TransitionFlipFromRight

  • .TransitionCurlUp

  • .TransitionCurlDown

  • .TransitionCrossDissolve

  • .TransitionFlipFromTop

  • .TransitionFlipFromBottom

如果我们有多个目标视图,想进行不同的过渡转变动画怎么办?那我们就创建多个目标视图的容器视图,尺寸与目标视图一致,放置在合适的位置:

 

从上图中可以看出,我们在屏幕上放置了四个容器视图,显而易见,我们要分别对这四个容器视图添加过渡转变动画。当然容器视图里要添加什么样的视图随个人喜好。

viewDidLoad()方法中添加如下代码:

[cpp] view plaincopy

  1. UIView.transitionWithView(self.ipadContainerView, duration: 1.5, options: [.CurveEaseOut, .TransitionFlipFromBottom], animations: {  

  2.     self.ipadContainerView.addSubview(self.ipadView)  

  3. }, completion: nil)  

  4.   

  5. UIView.transitionWithView(self.iphoneContainerView, duration: 1.5, options: [.CurveEaseOut, .TransitionFlipFromLeft], animations: {  

  6.     self.iphoneContainerView.addSubview(self.iphoneView)  

  7. }, completion: nil)  

  8.   

  9. UIView.transitionWithView(self.webContainerView, duration: 1.5, options: [.CurveEaseOut, .TransitionFlipFromRight], animations: {  

  10.     self.webContainerView.addSubview(self.webView)  

  11. }, completion: nil)  

  12.   

  13. UIView.transitionWithView(textContainerView, duration: 2, options: [.CurveEaseOut, .TransitionCrossDissolve], animations: {  

  14.     self.textContainerView.addSubview(self.textView)  

  15. }, completion: nil)  

通过上述代码可以看出,我们对四个容器视图分别添加了过渡转变动画,并且options参数使用了.CurveEaseOut和不同的过渡转变动画选项。编译运行看看效果:

                                        

是不是有点儿意思!不过细心的朋友应该发现了,过渡转变动画的方法没有delay这个很有用的属性,这就导致过渡转变动画都是同时发生,不能设置延迟时间。不过我们可以曲线救国,自己写一个delay方法:

[cpp] view plaincopy

  1. func delay(seconds: Double, completion:()->()) {  

  2.     let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64( Double(NSEC_PER_SEC) * seconds ))  

  3.     dispatch_after(popTime, dispatch_get_main_queue()) {  

  4.         completion()  

  5.     }  

  6. }  

然后我们修改viewDidLoad()方法中的代码如下:

[cpp] view plaincopy

  1. delay(0, completion: {  

  2.    UIView.transitionWithView(self.ipadContainerView, duration: 1.5, options: [.CurveEaseOut, .TransitionFlipFromBottom], animations: {  

  3.        self.ipadContainerView.addSubview(self.ipadView)  

  4.    }, completion: nil)  

  5. })  

  6.   

  7. delay(1, completion: {  

  8.             UIView.transitionWithView(self.iphoneContainerView, duration: 1.5, options: [.CurveEaseOut, .TransitionFlipFromLeft], animations: {  

  9.                 self.iphoneContainerView.addSubview(self.iphoneView)  

  10.                 }, completion: nil)  

  11.  })  

  12.           

  13. delay(2, completion: {  

  14.             UIView.transitionWithView(self.webContainerView, duration: 1.5, options: [.CurveEaseOut, .TransitionFlipFromRight], animations: {  

  15.                 self.webContainerView.addSubview(self.webView)  

  16.                 }, completion: nil)  

  17. })  

  18.   

  19. delay(3, completion: {  

  20.             UIView.transitionWithView(self.textContainerView, duration: 2, options: [.CurveEaseOut, .TransitionCrossDissolve], animations: {  

  21.                 self.textContainerView.addSubview(self.textView)  

  22.                 }, completion: nil)  

  23.  })  

我们将每个过渡转变动画延迟1秒进行,编译运行看看效果:

                                        

现在的效果是不是更好了呢! : ]

移除视图

过渡转变动画同样可以用来移除视图。我们在屏幕底部添加一个UIButton,当点击这个按钮的时候,通过过渡转变动画移除按钮上方的那两排字,并且改变屏幕背景色。go()方法是按钮连接在代码中的Touch Up Inside方法,在该方法中添加如下代码:

[cpp] view plaincopy

  1. UIView.animateWithDuration(0.5, animations: {  

  2.             self.view.backgroundColor = UIColor(red: 252.0/255.0, green: 155.0/255.0, blue: 65.0/255.0, alpha: 1)  

  3. })  

编译运行看看效果:

                                        

替换视图

在这一节我们将要学习过渡转变动画的另一个方法,替换视图方法。我设计的场景是当点击Go按钮后,除了上一节中的动画效果以外,iPad、iPhone、Web视图也会移位并且替换为别的视图,我们继续在go()方法中的添加如下代码:

[cpp] view plaincopy

  1. UIView.animateWithDuration(1, delay: 0, options: [], animations: {  

  2.      self.iphoneView.frame = CGRectMake(0, 0, 334, 72)  

  3.      self.iphoneContainerView.frame = CGRectMake(26, 130, 334, 72)  

  4.   }, completion: {  

  5.         (flag: Bool) in  

  6.                 if flag {  

  7.                         UIView.transitionFromView(self.iphoneContainerView, toView: self.supportIphone, duration: 0.33, options: .TransitionCrossDissolve, completion: nil)  

  8.                 }  

  9.  })  

  10.           

  11. UIView.animateWithDuration(1, delay: 1, options: [], animations: {  

  12.     self.ipadView.frame = CGRectMake(0, 0, 334, 72)  

  13.     self.ipadContainerView.frame = CGRectMake(26, 242, 334, 72)  

  14.   }, completion: {  

  15.         (flag: Bool) in  

  16.                 if flag {  

  17.                         UIView.transitionFromView(self.ipadContainerView, toView: self.supportIpad, duration: 0.33, options: .TransitionCrossDissolve, completion: nil)  

  18.                 }  

  19. })  

  20.           

  21. UIView.animateWithDuration(1, delay: 2, options: [], animations: {  

  22.     self.webView.frame = CGRectMake(0, 0, 334, 72)  

  23.     self.webContainerView.frame = CGRectMake(26, 354, 334, 72)  

  24. }, completion: {  

  25.         (flag: Bool) in  

  26.                 if flag {  

  27.                         UIView.transitionFromView(self.webContainerView, toView: self.supportWeb, duration: 0.33, options: .TransitionCrossDissolve, completion: nil)  

  28.                 }  

  29. })  

我们来解释一下上述的代码,拿iPhone视图为例,首先通过动画属性动画改变它的尺寸大小和位置。然后在completion闭包中添加替换视图方法,该方法有五个参数:

  • fromView:被替换的视图。

  • toView:替换之后的视图。

  • duration:动画持续时间。

  • options:动画选项。

  • completion:动画执行结束后执行该闭包中的代码。

要注意的是该方法的作用视图可以是容器视图,也可以是目标视图。编译运行看看效果:

                                        

显示/隐藏视图

过渡转变动画也可以用于显示或隐藏视图,这里给出伪代码供参考:

[cpp] view plaincopy

  1. UIView.transitionWithView(self.someContainerView, duration: 1.5, options: [.CurveEaseOut, .TransitionFlipFromBottom], animations: {  

  2.     self.someView.hidden = true  

  3.     // self.someView.hidden = false  

  4. }, completion: nil)  

结束语

过渡转变动画有很多动画选项,大家可以自行试试,找出自己喜欢的或最合适的过渡转变动画选项,并且可以尝试过渡转变动画和属性动画的组合,可以使你们的App更加有趣。好了今天就到这里。


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!