如何使用autolayout的UIView加入动画
hi,all:
在经过了一番犹豫之后,我决定将我自己做的这个小APP的源代码发布给大家:
其出发点是和大家一起学习iOS开发,仅供学习參考之用。
之前代码是托管与gitlab
上的。今天我将其pull到github上来了,大家能够自行下载:git clone git@github.com:lihux/twentyThousandTomatoes.git没有安装git或者不会用的童鞋。
请猛戳github地址:https://github.com/lihux/twentyThousandTomatoes,进去之后选
择download zip下载就可以。
当我们对一个UIView使用了autolayout自己主动布局之后。也就意味着我们放弃了
传统的通过设置view的frame等方式手动的改动、确定这个view的位置、尺寸属性。
甚至从某种程度上讲,我们应该忘记view的frame属性:它的确定不再取决于我
(手动的直接修改),而是通过我们在storyboard或者code中提供的约束条件
(constraints),通过一个自己主动布局引擎(苹果为autolayout採用的是Cassowary
布局引擎,參考文档:点击打开链接),计算出这个view的frame。因此我们能够
觉得使用了autolayout的view的frame属性是一个仅仅读的属性。
在代码里觉得的修改
这个view的frame并不能对这个view的frame产生真正的效果(事实也确实如此)。
如今问题就来了,在曾经我们常常通过对一个view的frame的改动产生view移动
的动画效果,那么在使用了autolayout的view世界中我们该怎样实现同样的效果呢?
答案是。我们“将计就计”,通过改变这个view上的某个约束constraint然后在uiview的
animation block中触发layout来实现。
一、预期效果
以下我们以一个简单的样例来进行具体的说明:
如上图所看到的。整个界面都使用了autolayout,如今我们想实现这样一个效果:
当我们点击显示生日的button的时候,整个view向上滑动,同一时候向上推出一个日期
选取器(date picker)。类似于点击textfield。弹出键盘后整个界面为了避免被遮
住而向上移动的效果。
选取完毕日期后点击生日日期button或者完毕button整个view向
下缩回,同一时候date picker向下滑出可视范围。
二、实现细节
首先来看一眼storyboard中view的层级结构:例如以下图所看到的,从图中我们能够
看到。整个view的布局相当简单。就两级:根view和我们的date picker view,其
中date picker view包括了一个完毕button和系统的date picker。这种话。要实现
整个view和date picker view同一时候上移的效果,我们仅仅须要对根view和date picker
view同一时候做动画就可以。
考虑怎样实现根view的动画效果,这里我们能够巧妙的通过改动根view的
bounds属性来实现根view的上移效果。注意这里我们须要明确view的bounds属性
和frame属性的差别,前者是相对于当前view的本地坐标系而言的。而后者则是相
对于当前view的父view的坐标系而言的。
简单的讲,frame决定了一个view相对于父view的position和size信息。而
bounds则决定了当前view展示的内容相对于本地坐标系的位置。
这里我们将view
自身的可视内容和subviews能够看做一页纸上的内容信息,而view本身可以看成
是一枚放于纸上的放大镜,放大镜的大小不一定是和纸(content size)同样大小
的。bounds属性的作用就是确定这枚放大镜相对于纸的位置:一个bounds =
(0, 200, 300, 300)就意味着我们要将这枚放大镜向纸的下方移动200个points,但
放大镜相对于父view的位置仍是保持不变的,这样给我们的效果就是这个view(显
示的内容)向上移动了200个points.
修改bounds的origin属性并不会修改这个view的frame,通过这样的展示内容的
移动给我们产生一种view向上移动了的幻觉。如上图中。“哪个位置...”为成为我们
放大镜中看到的第一行。
根view上移动画的效果攻克了,以下我们再来看日期选取器date picker。在
storyboard中对其添加的约束例如以下:定高207、trailing/leading/top相对于super
view (根view)的位置。
确定date picker view y轴方向上下移动的约束显然是top约束。点开top约束,
能够看到该约束的具体内容:
一个约束能够描写叙述为:firstItem.attributeA = secondItem.attributeB * multipler
+ constant。
结合上图我们能够得出date picker view的top约束为
datePickerView.Top = topLayoutGuide.bottom * 1 + 400
我们能够通过改动这里的constant值来改动这个top约束以达到预期效果,事实
上通过改动而不是删除旧的constraint再加入新的constraint也正是苹果所推荐的,
在NSLayoutConstraint.h头文件里有例如以下说明:
这样。date picker view的上下移动就能够通过获取并改动其top约束来实现。
须要注意的是在代码中获取datepicker view的top约束实际上是要在其父view的
constraints数组中查找。这是由于每一个view的constraints数组中保存的实际上是
layout 子view所需的约束的集合。
我们还要定义个辅助BOOL变量,已推断date picker view是否以弹出:
<span style="font-size:18px;">@property (nonatomic, assign) BOOL hasShowPickerView;</span>
接下来定义一个辅助函数,用于查找date picker view的top约束并改动其
constant属性为给定的值:
- (void)replacePickerContainerViewTopConstraintWithConstant:(CGFloat)constant
{
for (NSLayoutConstraint *constraint in self.pickerContainerView.superview.constraints) {
if (constraint.firstItem == self.pickerContainerView && constraint.firstAttribute == NSLayoutAttributeTop) {
constraint.constant = constant;
}
}
}
代码里我们在picker container view (即文中的date picker view)的
superview的constraints属性中查找,假设发现firstItem和firstAttribute属性各自是
date picker view和top,则该constraint即为目标约束,然后改动其constant属性。
在view首次被载入的时候我们想确保date picker view 处于整个view的最底部即隐
藏的状态,因而我们在viewcontroller的viewDidLoad方法中调用辅助方法改动一下
date picker view的top约束:
<span style="font-size:18px;">[self replacePickerContainerViewTopConstraintWithConstant:self.view.frame.size.height];</span>
在首次点击birthday button的时候动画改动根view的bounds和date picker
view的top constraint。注意上移gap的计算。
再次点击birthday button的时候将根
view的bounds恢复到正常值,date picker view的top constraint也恢复到viewDidLoad
中设置的值:
<span style="font-size:18px;">- (IBAction)didTapOnBirthdayButton:(id)sender
{
self.hasShowPickerView = !self.hasShowPickerView;
if (self.hasShowPickerView) {
CGRect birthdayButtonFrame = self.birthdayButton.frame;
birthdayButtonFrame = [self.view convertRect:birthdayButtonFrame fromView:self.birthdayButton.superview];
CGFloat birthdayButtonYOffset = birthdayButtonFrame.origin.y + birthdayButtonFrame.size.height;
CGFloat gap = birthdayButtonYOffset - (self.view.frame.size.height - self.pickerContainerView.frame.size.height);
CGRect bounds = self.view.bounds;
if (gap > 0) {
bounds.origin.y = gap;
} else {
gap = 0;
}
[self replacePickerContainerViewTopConstraintWithConstant:birthdayButtonYOffset];
[UIView animateWithDuration:0.25 animations:^{
self.view.bounds = bounds;
[self.view layoutIfNeeded];
}];
} else {
[self replacePickerContainerViewTopConstraintWithConstant:self.view.frame.size.height];
CGRect bounds = self.view.bounds;
bounds.origin.y = 0;
[UIView animateWithDuration:0.25 animations:^{
self.view.bounds = bounds;
[self.view layoutIfNeeded];
}];
}
}
</span>
上述代码中的[self.view layoutIfNeed]去掉也是没问题的。可能比較费解的是
根view.bounds.origin.y的上移gap的计算以及top constraint的constant值的计算。
关键实在真正理解view的frame和bounds的意义。
至此程序达到了预期的效果。以下的gif图展示了动画效果。
1.竖屏:
2.横屏:
三、小结
在使用autolayout之前我们敲代码控制界面的构成就好比是开一辆手动挡的汽
车,尽管频繁换挡(改动frame)非常繁琐。却也非常享受那种能够全然控制汽车档位的
自由感。使用了autolayout之后则一下子升级为了自己主动挡汽车,切换档位的活不再由
我们直接操作。而仅仅能通过油门(constraints)的大小来间接的改变汽车的档位。
在
自己主动挡汽车里,我们必需要放弃直接控制档位的想法。那是不可能的了,我们必需要
学会通过熟练掌握脚下的油门和刹车来控制车速。在习惯了自己主动挡之后。相信大家也
一样可以得心应手的做自己想做的事情。
版权声明:本文博主原创文章,博客,未经同意不得转载。
如何使用autolayout的UIView加入动画的更多相关文章
- 细数AutoLayout以来UIView和UIViewController新增的相关API
本文转载至 http://www.itjhwd.com/autolayout-uiview-uiviewcontroller-api/ 细数AutoLayout以来UIView和UIViewContr ...
- iOS开发UI篇—核心动画(UIView封装动画)
iOS开发UI篇—核心动画(UIView封装动画) 一.UIView动画(首尾) 1.简单说明 UIKit直接将动画集成到UIView类中,当内部的一些属性发生改变时,UIView将为这些改变提供动画 ...
- ios uiview封装动画(摘录)
iOS开发UI篇—核心动画(UIView封装动画) 一.UIView动画(首尾) 1.简单说明 UIKit直接将动画集成到UIView类中,当内部的一些属性发生改变时,UIView将为这些改变提供动画 ...
- iOS开发——动画编程Swift篇&(一)UIView基本动画
UIView基本动画 // MARK: - UIView动画 ------------------------------------- // MARK: - UIView动画-淡入 @IBActio ...
- IOS UIVIEW layer动画 总结(转)
转发自:http://www.aichengxu.com/article/%CF%B5%CD%B3%D3%C5%BB%AF/16306_12.html IOS UIVIEW layer动画 总结, ...
- 用layer添加UIView的动画
项目有时会遇到用UIView 添加动画的情况,这里我觉得在layer上添加动画比较好,因为可以详细地设定动画属性,方便理解 下面是一个旋转动画: -(void)roundBtnAction:(id)s ...
- IOS开发-UIView之动画效果的实现方法(合集)
http://www.cnblogs.com/GarveyCalvin/p/4193963.html 前言:在开发APP中,我们会经常使用到动画效果.使用动画可以让我们的APP更酷更炫,最重要的是优化 ...
- 17-UIKit(UIView的动画)
2. UIView的动画 UIView类本身具有动画的功能 2.1 概念 由UI对底层Core Animation框架的封装 可以轻松简单的实现动画效果 2.2 两种使用方式 1> Block ...
- iOS开发给UIView添加动画Animation
self.testView需要添加动画的view 1.翻转动画 [UIView beginAnimations:@"doflip" context:nil]; [UIView se ...
随机推荐
- ajax基本概念,方法
ajax Asynchronous javascript and xml异步的 javascript and XMLajax 是一门在不刷新网页的情况下,与服务器进行交互更新部分网页的技术: 传 ...
- linux--关于shell的介绍
下面是最近学习shell的一些知识点总结***博客园-邦邦酱好*** 1.什么是shell(1)Shell将我们输入的指令与Kernel沟通,好让Kernel可以控刢硬件来正确无误地工作.(2)我们总 ...
- ios7开发者必知
如果你想为iOS 设备开发app,你需要知道如何与软件交互,如何设计,你还要知道苹果独特的开发理念和开发工具.真正的能力还需要成功地从其他行业领域借鉴核心概念.最后把所有这些东西糅合进你的信息库中, ...
- Android 自己实现 NavigationView [Design Support Library(1)]
转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/46405409: 本文出自:[张鸿洋的博客] 一.概述 Google I/O 2 ...
- 使用dom4j创建和解析xml
之前工作中用到了,相信写java的都会碰到xml,这里写了两个方法,创建和解析xml,废话不多说,直接上代码 package xml; import java.io.File; import java ...
- ACE定时器
每一秒钟打印一行 http://www.tuicool.com/articles/Zb263e 计时器的打开和关闭封装 http://andylin02.iteye.com/blog/440572 自 ...
- 玩转web之javaScript(五)---js和jquery一些不可不知的方法(input篇)
很多时候我们都利用js和jquery中操作input,比如追加属性,改变属性值等等,我在这里简单的整理了一下,并在以后逐步补充. 1:删除input的某一属性. <input name=&quo ...
- 在小发现SQL字符串比较是不是他们的大写和小写敏感
声明:select petName from dbo.T_pet order by petName desc 成绩: petName An admin A的ascii码小于a,按理说应该 ...
- 走进C的世界-那些年我们常犯的错---keyword相关
近期一段时间參加一些面试,发现非常多细节的问题自己已经变得非常模糊了.对一些曾经常常遇到的错误.如今也说不出原因了. 而且在编码过程中也相同犯这些错误. 特别写一个博客来记录这些我们常常遇到的错误.自 ...
- 详细说明XML分解(两)—DOM4J
第一部分关于博客XML三接口,同时也为学习DOM4J该分析工具做准备.一般解析器基本上都实现了DOM和SAX这两组接口,DOM4J自然也不例外..DOM4J仅仅是经常使用解析器的当中一种,只是既然是实 ...