View Animations(三)Transitions

Transitions

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

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

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

一: Transitions实例

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

添加一个视图

View Animations(三)Transitions_第1张图片
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)

View Animations(三)Transitions_第2张图片
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)

View Animations(三)Transitions_第3张图片
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”

View Animations(三)Transitions_第4张图片
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,这种过渡使得视图像一张纸在合法的平板上被翻转一样,看起来像下面一样

View Animations(三)Transitions_第5张图片
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。 我认为它非常适合横幅图形:

View Animations(三)Transitions_第6张图片
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应用程序添加一些严肃的优雅的动画。

你可能感兴趣的:(View Animations(三)Transitions)