View Animations(三)Transitions

Transitions

在前两章中,您学习了如何基于视图的动画属性(如位置和alpha)创建动画。但是,如何处理想要增加或删除视图的情况呢?

您可以使用前面章节中的方法,并在界面中进出视图。不过,本章将向您展示如何使用转换为视图的任何一组更改设置动画

转场是可以应用于视图的预定义动画。这些预定义的动画不会尝试在视图的开始和结束状态之间进行插值。相反,您将设计动画,以便各种状态的变化显得自然

一: Transitions实例

为了更好地理解何时使用过渡动画,本节将向您介绍可以使用Transitions动画的各种动画场景

添加一个视图

image

要在屏幕上添加一个新视图的动画,可以调用与前面章节中使用的方法类似的方法。这次的区别在于你会选择一个预定义的过渡效果,并为所谓的动画容器视图设置动画效果

该过渡为容器视图添加了动画,并且在动画运行时,添加到视图的任何新视图都以子视图的形式出现

为了更好地解释如何为容器视图设置动画,以及何时执行子视图之间的转换,请考虑以下代码片段:

var animationContainerView: UIView!
override func viewDidLoad() {
  super.viewDidLoad()
  //set up the animation container
  animationContainerView = UIView(frame: view.bounds)
  animationContainerView.frame = view.bounds
  view.addSubview(animationContainerView)
}
override func viewDidAppear(_ animated: Bool) {
  super.viewDidAppear(animated)
  //create new view
  let newView = UIImageView(image: UIImage(named: "banner"))
  newView.center = animationContainerView.center
  //add the new view via transition
  UIView.transition(with: animationContainerView,
    duration: 0.33,
     options: [.curveEaseOut, .transitionFlipFromBottom],
    animations: {
      self.animationContainerView.addSubview(newView)
    },
    completion: nil
  )
}

在这种假设的情况下,您在视图控制器的viewDidLoad()中创建一个名为animationContainerView的新视图。 然后您定位并将此容器添加到视图

稍后,当您要创建动画过渡时,您将创建一个新的视图来进行动画处理; 这里叫做newView

要创建转换,请调用transition(with:duration: options:animations:completion:)。 这和标准的UIView动画方法几乎是一样的,但是在这种情况下,你提供了一个额外的参数视图,它作为过渡动画的容器视图

这里有一个新的动画选项.transitionFlipFromBottom,你还没有看到。 这是本章介绍中讨论的预定义转换之一. .transitionFlipFromBottom翻转视图的底部边缘作为视图翻转的“hinge”

最后,你在你的动画块中的动画容器中添加一个子视图,这会导致子视图在转换过程中出现

预定义过渡动画选项的完整列表如下所示:

  • .transitionFlipFromLeft
  • .transitionFlipFromRight
  • .transitionCurlUp
  • .transitionCurlDown
  • .transitionCrossDissolve
  • .transitionFlipFromTop
  • .transitionFlipFromBottom

移除视图(Removing a view)

image

使用过渡动画从屏幕中删除子视图非常类似于添加子视图。要使用过渡动画完成此操作,只需在动画闭包表达式中调用removeFromSuperview()就可以了

//remove the view via transition
UIView.transition(with: animationContainerView, duration: 0.33,
  options: [.curveEaseOut, .transitionFlipFromBottom],
  animations: {
    self.newView.removeFromSuperview()
  },
  completion: nil
)

和前面的例子一样,包装器转换将执行翻转动画,newView将在所有的结尾消失。

隐藏和展示视图(Hiding/showing a view)
[站外图片上传中...(image-7401e1-1512631213095)]

到目前为止,在本章中,您只学习了改变视图层次结构的转换。 这就是为什么你需要一个容器视图的过渡 - 这使得层次结构的变化在上下文中

相比之下,您不需要担心设置容器视图来隐藏和显示观点。 在这种情况下,转换使用视图本身作为动画容器

考虑下面的代码来使用转换来隐藏子视图:

//hide the view via transition
UIView.transition(with: self.newView, duration: 0.33,
  options: [.curveEaseOut, .transitionFlipFromBottom],
  animations: {
    self.newView.isHidden = true
  },
  completion: nil
)

在这里你传入你想要显示或隐藏的视图作为转换的第一个参数transition(with:duration:options:animations:completion:)。 你之后所做的就是在动画块中设置你的视图的isHidden属性,并且瞧,过渡动画开始

替代视图(Replacing a view with another view)

image

用另一个视图替换一个视图也是一个简单的过程。您只需传入现有视图作为第一个参数,并将toView:参数设置为您希望替换的视图,如下所示

//replace via transition
UIView.transition(from: oldView, to: newView, duration: 0.33,
  options: .transitionFlipFromTop, completion: nil)

UIKit为您提供了多少重要的功能?

在本章的其余部分中,您将通过转换来展示和隐藏UI元素,并学习一些可以引入自己的项目的新动画技巧

二: (混合转场)Mixing in transitions

您将继续在本章中的Bahama Air登录屏幕项目上工作; 你已经创建了一些引人注目的动画在这个屏幕上的意见,添加一点点的登录表单,并使按钮反应被挖掘

接下来,您将模拟一些用户身份验证并为几个不同的进度消息添加动画。一旦用户点击登录按钮,您将显示消息,包括“Connecting...”,“Authorizing...”和“Failed”

image

如果您还没有完成前面的章节,您可以从本章的资源文件夹中的入门项目开始。如果你已经在自己的项目的最后几章中的例子,很好的工作! 您可以继续使用现有的项目

打开ViewController.swift并查看viewDidLoad(),这种方法的一部分添加了一个隐藏的图像视图存储在类变量状态。代码然后创建一个文本标签,并将其作为子视图添加到状态

您将使用状态向用户显示进度消息。 消息来自消息数组,这是starter项目中包含的另一个类变量。

将以下方法添加到ViewController

func showMessage(index: Int) {
  label.text = messages[index]
  UIView.transition(with: status, duration: 0.33,
    options: [.curveEaseOut, .transitionCurlDown],
    animations: {
      self.status.isHidden = false
    },
    completion: {_ in
            //transition completion
  } )
}

这个方法带有一个名为index的参数,你可以使用它来将label的值设置为基于index的消息内容

上面还有一个新的动画选项:.transitionCurlDown,这种过渡使得视图像一张纸在合法的平板上被翻转一样,看起来像下面一样

image

现在是时候锻炼你的新showMessage(index :)方法。 在login()中找到以下代码块:

animations: {
  self.loginButton.bounds.size.width += 80.0
}, completion: nil)

这是您现有的动画块,当用户点击它时,会使登录按钮反弹。 你会添加一些新的东西 - 一个完成封闭 - 这个动画,调用showMessage(index:).

将完成的nil参数值替换为以下闭包表达式:

completion: { _ in
  self.showMessage(index: 0)
}

闭包需要一个Bool参数,它告诉你动画是否成功完成,或者在动画完成之前被取消

注意:上面的完成关闭具有完成的单个参数。因为你不关心它是否完成,Swift允许你跳过绑定参数,把“_”放在它的位置。

在闭包中,只需调用索引为0的showMessage即可显示消息数组中的第一条消息

建立并运行你的项目; 点击登录按钮,你会看到状态标题出现你的第一个进度信息
[站外图片上传中...(image-e206e0-1512631213095)]

你看到横幅像一张纸一样卷起来了吗? 这是一个非常好的方式来关注通常只显示为静态文本标签的消息。

注意:你的一些动画似乎很快运行,不是吗?有时确保动画在正确的位置以正确的顺序发生是非常棘手的。 或者,也许你只是想让事情发生得更慢,所以你可以欣赏效果!要在不改变代码的情况下减慢应用程序中的所有动画,请从iPhone Simulator菜单中选择“最前面的应用程序中的调试/切换慢动画”。 现在点击您的应用程序中的登录按钮,享受生动的慢动作的动画和过渡!

对于下一个动画,您首先需要保存横幅的初始位置,以便您可以将下一个横幅放在正确的位置。

将以下代码添加到viewDidLoad()的末尾,将横幅的初始位置保存到名为statusPosition的属性中:

  statusPosition = status.center

现在,您可以开始设计视图动画和过渡的混合。

添加以下方法通过标准从屏幕上删除状态消息动画:

func removeMessage(index: Int) {
  UIView.animate(withDuration: 0.33, delay: 0.0, options: [],
    animations: {
      self.status.center.x += self.view.frame.size.width
    },
    completion: { _ in
      self.status.isHidden = true
      self.status.center = self.statusPosition
      self.showMessage(index: index+1)
    }
) }

在上面的代码中,您可以使用您的老朋友animate(withDuration:delay:options:animations:completion:)将状态移动到屏幕可见区域之外。

当动画在完成关闭时完成时,将状态移回原始位置并隐藏。 最后你再次调用showMessage,但这次你传递下一条消息的索引来显示

将标准动画与转换相结合非常容易:只需调用相应的API,UIKit就会调用背景中相应的Core Animation

现在,您需要完成showMessageremoveMessage之间的调用链,以模拟真实的身份验证过程

找到showMessage(index :)并用下面的代码替换注释//转换完成:

delay(2.0) {
  if index < self.messages.count-1 {
    self.removeMessage(index: index)
  } else {
//reset form
} }

一旦转换完成,你等待2.0秒,并检查是否有任何剩余的消息。如果是这样,通过removeMessage(index :)删除当前消息。 然后,您可以在removeMessage(index :)
的完成块中调用showMessage(index :)来按顺序显示下一条消息。

注意:delay(_:completion :)是一个方便的函数,在经过延迟后运行一段代码。 它在ViewController.swift的顶部定义。 在这里你用它来模拟通常的网络访问延迟。

再次构建并运行您的项目; 享受由此产生的动画序列,其如此更新认证进程消息
[站外图片上传中...(image-e6c9b9-1512631213095)]

转换是动画知识的一个小而重要的子集,以保留在你的比喻工具箱中,因为它们是在UIKit中创建3D风格动画的唯一方法。

如果您期待学习更精细的3D效果,您将有机会在第六部分“3D动画”中详细讨论Core

在进入下一部分之前,请尝试尝试本章中的挑战。既然你在前三章学到了很多关于动画的知识,一个挑战是不够的 - 我给了你三个Animation和3D图层转换。

这些挑战使您有机会在Bahama Air登录屏幕上完成开发工作 - 同时也是您面临的第一个挑战。活泉!

#######挑战

挑战一
到目前为止,您只能看到其中一个内置的过渡动画。 你不是很好奇看到别人是什么样子吗?

在这个挑战中,你可以尝试所有其他可用的过渡动画,并使用你最喜欢的动画进度信息横幅

打开ViewController并在showMessage(index :)中找到指定过渡动画的行.transitionCurlDown`

 UIView.transitionWithView(status, duration: 0.33, options:
  [.curveEaseOut, .transitionCurlDown], an

.transitionCurlDown替换为其他任何可用的过渡动画,然后构建并运行项目以查看它们的外观。 以下是可用转换的列表:

.transitionFlipFromLeft
.transitionFlipFromRight
.transitionCurlUp
.transitionCurlDown
.transitionCrossDissolve
.transitionFlipFromTop
.transitionFlipFromBottom

哪一个你认为在这个屏幕上的其他动画效果最好?
如果你没有最爱,请尝试我的最爱过渡:.transitionFlipFromBottom。 我认为它非常适合横幅图形:

image

挑战二
对于这个挑战,您可以通过撤消一旦点击登录按钮后运行的所有动画,将表单重置为初始状态。 这样,如果登录失败,当用户再次点击登录按钮时,他们会看到所有的动画再次发生

以下列出了完成这一挑战所需的一般步骤:

  • 1:创建一个新的空方法resetForm()并从你的代码中调用它占位符评论//重置表单的生命。
  • 2:在resetForm()中使用transition(with:duration:options:animations:completion :)将状态的可见性设置为隐藏和居中为self.statusPosition。 这应该重置旗帜到其初始状态。 使用0.2秒的时间进行转换。
  • 3: 如果隐藏横幅的转换使用与显示横幅的动画完全相反的动画,那将会很好。 例如,如果您通过.transitionCurlDown显示横幅,则使用.transitionCurlUp将其隐藏。 相反
    .transitionFlipFromBottom将是.transitionFlipFromTop...等等
  • 4: 接下来,在resetForm()中添加一个对animate(withDuration:delay:options:animations:completion :)的调用。 在动画闭包模块中进行以下调整
    • self.spinner(“登录”按钮内的活动指示器)移动到(-20.0,16.0)的原始位置,
    • self.spinneralpha属性设置为0.0以隐藏它。
    • 将“登录”按钮的背景颜色调回原始值:UIColor(red: 0.63, green: 0.84, blue: 0.35, alpha: 1.0).
    • 继续重置对“登录”按钮的所有更改,然后减小由80.0点的bounds.size.width属性
    • 最后,将该按钮移回密码字段下的原始位置减少60.0点

如果您在身份验证过程中精确地颠倒了所有的动画,屏幕一旦所有的认证信息都显示出来,
[站外图片上传中...(image-c2bfe3-1512631213095)]

做得好! 而现在这一章的über挑战...

[站外图片上传中...(image-571d0-1512631213095)]

关于挑战:在背景中动画云彩
如果背景中的那些云在屏幕上慢慢地移动,并从另一侧再次出现,这不是很酷吗?
是的,这将是非常酷 - 这就是你的挑战!

四个云图像视图已经连线到ViewController的四个插座,所以你很好走。 你可以尝试使用你自己新发现的过渡动画知识来自己动手,或者你可以按照下面的配方

  • 1: 创建一个签名为animateCloud(cloud:UIImageView)的新方法,并在其中添加代码。
  • 2: 首先,计算平均云速度。 假设云应该在大约60.0秒内穿过屏幕的整个长度。 调用常量cloudSpeed并将其设置为60.0/view.frame.size.width
  • 3: 接下来,计算动画将云移动到屏幕右侧的持续时间。 请记住,云不是从屏幕的左边缘开始,而是从随机点开始。 你可以计算正确的持续时间,通过考虑云需要遵循的路径的长度,并将结果乘以平均速度:`(view.frame.size.width - cloud.frame.origin.x)*cloudSpeed
  • 4: 然后调用animate(withDuration:delay:options:animation:completion :)以上面刚计算的持续时间。 您需要从中创建TimeInterval的实例,因为编译器不会为您确定正确的类型:TimeInterval(duration)。 对于选项参数使用.curveLinear; 这是少数几次使用动画而没有缓动的情况之一。 云层背景自然很深,所以他们的运动看起来应该是平坦的。
  • 5: 在动画闭包表达式中,将云的frame.origin.x属性设置为self.view.frame.size.width。 这将云移动到屏幕区域之外。
  • 6: 在完成关闭块内,将云从当前位置移动到屏幕另一边的外部。 不要忘记像本章前面所做的那样,使用“_”来跳过闭包参数。 要正确定位云,请将其frame.origin.x设置为-cloud.frame.size.width
  • 7: 仍然在完成关闭工作,添加一个调用animateCloud(),以便云重新在屏幕上动画。
  • 8: 最后,将以下代码添加到viewDidAppear()的末尾,以启动所有四个云的动画
animateCloud(cloud1)
animateCloud(cloud2)
animateCloud(cloud3)
animateCloud(cloud4)

这应该使所有四个云彩慢慢地穿过屏幕创造一个好,不引人注目的作用。
如果您完成了本章的挑战,恭喜! 他们很难!:]
过去几章有很多信息需要消化,但是你采取了一种僵硬的,静态的登录表单,并将其转化为对用户的引人注目和有趣的体验:

[站外图片上传中...(image-decc0f-1512631213095)]

现在是时候从新材料中稍微休息一下,把所有的视图动画知识加入测试! 在下一章中,您将使用各种各样的实际操作来为Bahama Air应用程序添加一些严肃的优雅的动画。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容