笔记-动画篇-layout动画初体验

约束动画的文章要比预计的迟迟来临,最大的原因是没有找到我认为的足够好的动画来讲解约束动画 —— 当然了,这并不是因为约束动画太难。相反,因为约束动画实在太简单了,反而没有足够多的简单动画素材让我选用。下面这个动画取自于朋友公司的app,我仿做了一个,作为今天的demo,具体效果如下:

约束动画

关于约束

在这一小节我会简单的介绍一下约束的用法,如果您已经在使用storyboard进行开发了,那么可以跳过这一节。 假设现在有这么一个需求,你需要将文章显示在界面的中间位置,大致是左右空30pt、上方间隔20pt,效果图如下:

需求界面

你满心不在意的想这个任务多简单啊,于是挥洒的写下了这么一段代码:

self.textView = [[UITextView alloc] initWithFrame: CGRectMake(30, 20, self.view.bounds.size.width - 60, 0)];

self.textView.text = ..........

[self.textView sizeToFit];

然后运行你的代码,ok,效果不错。但请等等,按住command + 左右方向键,你的界面变成了这样:

错误的界面

你很快就意识到问题所在。好的,你接收了屏幕转向的通知UIApplicationWillChangeStatusBarOrientationNotification,然后在回调里面重新修改了文本的宽度:

- (void)notifyToAdjustTextView: (NSNotification *)notification

{

switch ([UIDevice currentDevice].orientation) {

case UIDeviceOrientationLandscapeLeft:

case UIDeviceOrientationLandscapeRight:

CGRect frame = self.textView.frame;

frame.size.width = self.view.bounds.size.height - 60;

self.textView.frame = frame;

[self.textView sizeToFit];

//more

......

}

}

这次再次运行你的代码,不管你怎么转向,文本都稳稳的显示在中心,你成功了!但是这样工作有些太繁杂了 —— 你做了这么多的工作只是为了解决一个布局问题。因此,这就提及到了我们今天的主题:约束

在你新建的项目中总会存在一个Main.storyboard,让我们打开这个文件,在xcode为我们创建好的控制器里面直接添加文本:

故事板使用

点击选中textView,xcode为我们提供了下方的几个按钮来给我们的控件添加约束。我在这里给控件添加了距离上方20pt、左右距离边缘30pt的约束,完成后点击Add 3 Constraints约束就算添加完成了:

添加约束

现在运行你的项目,尝试屏幕转向,无论如何文本总是距离上方20pt,左右距离30pt。使用约束让我们的工作更加的简单不是吗?

所有的动画都是将一连串的计算展示开来的过程,约束动画也不例外,那么约束是如何计算的呢?以上面的基础约束demo为例,在我们为文本控件添加了约束之后,故事板上的textView多了一些直线,每一条直线代表一个约束。双击这个约束我们可以设置更多东西。

约束的相关值

以这个约束为例,所有的约束计算都遵循这样的计算: TextView.Left = 1 * superView.Left + 30

父视图的left坐标点位置总是基于0pt的位置进行计算的,因此与父视图的约束计算总是以constant的值为结果。因此修改constant的大小并重新绘制界面可以产生动画。

关于autolayout使用的更多教学可以看这篇文章

动画分析

在开工之前分析代码的实现过程可以让我们对动画的实现有更清晰的了解。可以看到,动画建立在tableView的滚动条件上,那么监听tableView的滚动偏移是动画实现的核心部分。(ps:为什么是kvo而不是直接代理回调呢?当我们无法保证工程中tableView的代理和动画实现方是否为同一对象时,使用kvo是最稳妥的选择)

根据用户滑动的时候,我们可以总结出下面这几个动画效果:

  • 导航栏标题淡出颜色渐变
  • 导航栏标题上移
  • 红色的背景层上移并隐藏
  • 倒计时信息和文本信息上移显示在导航栏中

综合这些信息我写了一些需要用到的宏定义:

#define OBSERVERKEY @"contentOffset"///<监听属性

#define MAXMOVE 64.0///<滚动最大值

#define TITLEMAXMOVE 16.0 ///<导航文本位移最大值

#define TOPANDBOTTOMCONSTANT 9///<红色背景上下间距约束值

本文的动画可以归类为视觉差动画,通过利用不同视图的层次在视图移位形成视觉动画效果,因此我们可以先将动画中发生了视觉位移的视图的层次写出来,这样会帮助我们更好的实现动画。

在动画过程中,红色的背景层上移之后就不再显示,因此红色的背景图层肯定位于导航栏的蓝色视图下方。而倒计时和文本信息上移之后依旧显示,可以肯定这些视图处在导航栏视图上面。因此可以得出这么一个层次:文本信息和倒计时控件 -> 导航栏 -> 红色背景。另一方面如果在动画中同时移动这些文本信息和倒计时控件,代码量肯定很多,所以我们可以把这些控件全部当做一个透明的UIView的子视图,然后简单的移动这个UIView就可以了。下面我放上一张官方文档中苹果对于导航栏控制器的视图层次图:

导航栏控制器层次图

结合上面的结论,我们可以知道:

  • 透明视图处在Custom view hierarchy和Navigation View中间
  • 红色背景处在Navigation view和UIWindow之间

由于在本文的demo中动画控制器作为一级界面,基于简(tou)单(lan)方(shao)便(xie)的原则,我使用了UIViewController,并在上面添加了一个冒充导航栏的view来实现的。如果动画实现需要在二级以上的界面实现,你可能需要继承UINavigationController来自定义这个效果。

准备工作

首先我们在故事板中将界面搭建起来,我们从右下侧的控件栏拖出来一个UIView,注意这个UIView一定要拖拉到顶部在状态栏以内,否则你创建的约束顶部将会以状态栏下方开始,比预期的位置下移了20pt

自定义导航栏

其次在这个导航栏view上面拉进来一个UILabel关联文件名为navigationTitle,并设置约束为下、左右三个方向的约束为0,高度设置为44pt限制。文本居中,并修改为白色字体跟系统字体18号

添加导航标题label

最重要的是创建一个用于添加倒计时信息和一些label的透明视图,添加过程以及约束建立我就不再多说了,这是我添加完成之后的图示:

透明视图

完成这些工作之后,在左侧的视图层次栏里面移动这些视图的位置,确保红色背景的视图在导航栏视图的下方,内容透明视图在导航栏上方,接着就将一部分关键的约束关联到文件中。这些属性关联包括:

  • 滚动视图tableView
  • 透明视图内部子视图的居中约束titleCenterX
  • 透明背景视图的顶部约束contentTopConstraint
  • 红色背景视图的顶部约束backgroundTopConstraint
  • 还有伪装的导航栏标题文本的底部约束labelBottomConstraint

动画制作

首先我们需要监听tableView的滚动,这一部分代码我通常写在viewDidAppear:方法中。同样的,我喜欢在viewDidDisappear:中释放监听或者通知。

- (void)viewDidAppear:(BOOL)animated

{

[super viewDidAppear: animated];

[self.tableView addObserver: self forKeyPath: OBSERVERKEY options: NSKeyValueObservingOptionNew context: nil];

}

- (void)viewDidDisappear:(BOOL)animated

{

[self.tableView removeObserver: self forKeyPath: OBSERVERKEY];

}

在前面我已经说过滚动视图的动效了,那么我们在监听中需要获取滑动偏移,然后计算出滚动效果百分比:

CGFloat yOffset = self.tableView.contentOffset.y / MAXMOVE;

yOffset = MAX(0, MIN(1, yOffset));

这个数值会随着用户的滚动增大逐渐增加到1就不再增加,当到达1的时候就是动效的最终效果。在这过程中,导航栏的标题总共存在上移、渐变隐藏两种效果:

self.navigationTitle.alpha = 1 - yOffset;

self.labelBottomConstraint.constant = yOffset * TITLEMAXMOVE;

接着是红色的背景视图和倒计时这些控件的上移,其中所有的数据展示的控件都被添加到透明的视图上,所以我们只需要移动透明视图:

CGFloat yPoint = TOPANDBOTTOMCONSTANT - yOffset * MAXMOVE;

self.backgroundTopConstraint.constant = self.contentTopConstraint.constant = yPoint;

ok,所有组件的移动代码已经写完了,运行代码试一试。你发现了在上移过程中,透明视图的子控件似乎上移的有些过了。

正常情况下导航栏的高度是44pt,上面有个高度为20pt的状态栏,因此在动效中我设置的移动最大距离为44+20=64pt。而在demo中我们可以看到在移动64pt之后红色背景和透明视图确实移动到了64pt的中心,就是说在这两个视图高度为45pt的情况下,上面有9.5pt的尺寸进入了状态栏的范围中。因此,我们在移动动画过程中,如果要让文本信息能够在导航栏的位置上居中,我们还需要让这些文本信息下移9.5pt的距离。因此在监听回调中添加这么一句代码:

self.infoCenterX.constant = TOPANDBOTTOMCONSTANT * yOffset;

添加完这句代码再次运行,我们的动效就完成了!

尾言

我想说,作为自动约束动画的第一篇博客,我构思了很久。因为对于约束动画来说,这个demo的实现更像是UIView动画式的实现 —— 修改某些坐标值。但最终我还是觉得使用这个demo可以更快速的从UIView动画中转入约束动画内,至于下一篇我会讲解如何调用重绘方法来实现约束重制的动效实现以及在动画中替换更新约束。

时间: 2024-10-17 00:16:26

笔记-动画篇-layout动画初体验的相关文章

IOS开发核心动画篇---核心动画简介

iOS开发UI篇—核心动画简介 一.简单介绍 Core Animation,中文翻译为核心动画,它是一组非常强大的动画处理API,使用它能做出非常炫丽的动画效果,而且往往是事半功倍.也就是说,使用少量的代码就可以实现非常强大的功能. Core Animation是跨平台的,可以用在Mac OS X和iOS平台. Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程.不阻塞主线程,可以理解为在执行动画的时候还能点击(按钮). 要注意的是,Core Animation是直接作用

软件测试学习笔记week 3 --- 测试框架初体验

测试框架初体验 在这周的软件测试课上,第一次了解了软件测试框架的概念.软件测试框架包含的范围非常广,从自动化测试框架到单元测试框架以及性能测试框架.在上个寒假中,在学习Coursera的在线课程时发现普林斯顿的单元测试做得非常强大,从程序正确性到Time consuming甚至Memory consuming,几乎能发现程序中的每一处错误或者缺陷.因此,在上完了这周的课程后,我查阅了一些资料,做了这篇随笔记录了解到的单元测试的知识. 一.什么是测试框架 要认识测试框架,首先要对所谓框架有概念.框

(原)Unreal源码搬山-动画篇 自定义动画节点(一)

@author:黑袍小道 太忙了,来更新下,嘿嘿 前言: 本文是接着上文 Unreal搬山之动画模块_Unreal动画流程和框架,进行简单入门如何自定义动画图标的AnimNode. 正文: 一.AnimNode Unreal 4的AnimNode负责的骨骼动画的单项计算,最后汇总到AnimGraph有,然后交付给AnimInstance统一收集和处理. 下图未AnimNode相关的结构 二.CustomAnimNode 该例子实现修改指定的一系列骨骼,并再AnimGraphy预览和编辑 三.Un

jQuery-4.动画篇---自定义动画

jQuery中动画animate(上) 有些复杂的动画通过之前学到的几个动画函数是不能够实现,这时候就需要强大的animate方法了 操作一个元素执行3秒的淡入动画,对比一下2组动画设置的区别 $(elem).fadeOut(3000) $(elem).animate({ opacity:0 },3000) 显而易见,animate方法更加灵活了,可以精确的控制样式属性从而执行动画 语法: .animate( properties ,[ duration ], [ easing ], [ com

从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十六 ║ Vue前篇:ES6初体验 &amp; 模块化

缘起 昨天说到了<从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十五 ║ Vue前篇:JS对象&字面量&this>,通过总体来看,好像大家对这一块不是很感兴趣,嗯~~这一块确实挺枯燥的,不能直接拿来代码跑一下那种,不过还是得说下去,继续加油吧!如果大家对昨天的小demo练习的话,相信现在已经对JS的面向对象写法很熟悉了,如果嵌套字面量定义函数,如何使用this关键字指向.今天呢,主要说一下ES6中的一些特性技巧,然后简单说一下模块化的问题,好啦,开始今天的讲

iOS开发--动画篇之layout动画深入

"不得不说,单单是文章的标题,可能不足以说明本文的内容.因此,在继续讲述约束动画之前,我先放上本文要实现的动画效果." 编辑:Bison投稿:Sindri的小巢 约束动画并不是非常复杂的技巧,在你熟练使用约束之后,你总能创建些独具匠心的动画.在上一篇autolayout动画初体验中,我们根据监听列表视图的滚动偏移来不断改变约束值,从而制作出动画的效果.但上个动画的实现更像是我们制作了一帧帧连续的界面从而达成动画的效果 —— 这未免太过繁杂.而在本文我们将抛弃这种繁杂的方式,通过调用UI

leaflet开源地图库源码阅读笔记(一)——简介&amp;Demo初体验(by vczero)

一.简介 电子地图已经在O2O.生活服务.出行等领域布局,传统的GIS也孕育着互联网基因.传统GIS的图商有ESRI(Arc系列).四维.高德.超图.中地等等.在web互联网领域,百度和高德较为出色.但是开放源代码都远远做的不够,相比而言国外开源较多且丰富,最近认真研读了openlayers2/3和leaflet的源码,收获颇多,不仅加强对浏览器兼容性.HTML5.CSS3等基础,还增强了GIS的基础.本人现在也在一家互联网公司做js api的研发,因此,需要不断地吸取开源代码的营养. leaf

VSTO学习笔记(十五)Office 2013 初体验

原文:VSTO学习笔记(十五)Office 2013 初体验 Office 2013 近期发布了首个面向消费者的预览版本,我也于第一时间进行了更新试用.从此开始VSTO系列全面转向Office 2013平台,即VSTO 5.0. 本系列所有测试代码均在Visual Studio 2012 Ultimate RC + Office 2013 Professional Plus x64 Preview 上测试通过 为了配合Windows 8,微软的很多软件风格都逐渐Metro化,Office作为拳头

自定义控件三部曲之动画篇(九)——联合动画的代码实现

前言:为了梦想,行色匆匆,是否会错过眼前的风景?有时也会懊悔,为何当时没能好好享受时光,但如果当时真的跟他人一样,是否现在也会跟他人一样羡慕现在的自己? 相关博客: <Android自定义控件三部曲文章索引> 上几篇给大家分别讲了ValueAnimator和ObjectAnimator,相比而言ObjectAnimator更为方便而且由于set函数是在控件类内部实现,所以封装性更好.而且在现实使用中一般而言都是使用ObjectAnimator的机率比较大. 但ValueAnimator和Obj