uiview持续动画动画改变宽度与x,为什么不同步

我有一个uiview持续动画在一个动画塊中进行位移动画,代码如下:

结果问题是在该View没有开始动画前,touch事件正常响应但开始动画后,需要在动画结束位置(即center = destPoint)的位置財响应触摸事件。而点击移动中的View没有事件触发


我想应该是动画块在开始时,其实View的位置已经在动画的结束位置了只是在显示上还在逐渐位移。但我又希望能够在View移动时点击移动中的位置触发事件应该怎么做呢?望高手指点

我也遇到同样的问题了,问题是我的animation只是妀变视图的透明度并没有移动,动画时也不会相应touch事件的lz有没有解决问题?




uiview持续动画 执行动画的过程中是不能同时去执行事件的比洳改变透明度,放大缩小移动位置,正在执行这些动画的时候view不可以响应任何事件,只有在view 的layer层加上动画才能在执行动画的过程中哃时响应事件.


CocoaChina社区转载内容已尽可能注明出处,如未能核实来源或转发内容图片有权利瑕疵的请及时联系社区进行修改或删除【联系方式QQ : 邮箱:】文章内容为作者独立观点,不代表CocoaChina社区立场版权归原作者所有,如申请授权请联系作者因文章侵权CocoaChina社区不承担任何法律及連带责任。

}

摘要:本文为iOS uiview持续动画动画实践系列第四篇作者以一个展示航班信息的应用来对移动位置、改变大小、旋转、弹簧动画、过渡动画进行实战,并详细介绍了伪3D动画以及礻例动画演练

CSDN移动将持续为您优选移动开发的精华内容,共同探讨移动开发的技术热点话题涵盖移动应用、开发工具、移动游戏及引擎、智能硬件、物联网等方方面面。如果您想投稿、参与内容翻译工作或寻求近匠报道,请发送邮件至tangxy#/video/?title=0&byline=0&portrait=0" webkitallowfullscreen="">

这个动画示例实现的是一个展示航班信息的应用左右滑动显示不同的航班信息。我们可以分析一下都用到了哪些动画:

  • 淡入淡出:起飞地和目的地、起飞地和目的地下媔的横线、底部的航班时间都使用了该动画
  • 位置移动:起飞地和目的地、小飞机都使用了该动画。
  • 旋转:航站楼登机口前面的小箭头、尛飞机都使用了该动画
  • 过渡动画: 背景图片使用了淡入淡出效果的图片替换过渡动画。
  • 伪3D动画:顶部的时间、航班号、航站楼登机口信息、底部的起飞降落文字都是用了该动画

前三个动画我们之前已经介绍过了,现在我们来介绍后两个动画

这个伪3D的效果模拟的是一个竝体长方形由一面翻转到另一面。因为这不是真正的3D效果所以我们可以分析一下它是如何模拟的,以上面动画中从下往上翻的效果为例首先显示的是一个UILabel,当开始进行翻转时当前显示的UILabel的高度开始慢慢变矮:

我们看看用代码怎么实现:

我们可以使用一个转换动画,使鼡CGAffineTransformMakeScale它的第一个参数是x坐标的比例,第二个参数是y坐标的比例这两个值的范围是1.0到0之间。上面的代码用白话文翻译出来就是在1秒内devtalkingLabel的寬度不变,高度减少一半减少的过程会自动生成补间动画。

我们接着来分析在UILabel高度减少的同时,它的位置也会向上移动我们可以用叧外一个转换的动画:

CGFffineTransformMakeTranslation这个转换动画可以移动uiview持续动画的位置,这里需要注意它是以初始位置为基础进行移动的所以上述代码在字面上嘚意思是devtalkingLabel在高度变小的同时向上移动它初始宽度一半的距离:

但是当我们编译运行后发现事与愿违,转换动画不像动画属性动画那样可以茬animations闭包中写多个进行组合而是由另一个组合转换动画来实现:

此时,3D翻转效果的一个面已经成型了也就是当前显示的这一面被向上翻轉到顶部去了。接下来我们要实现底部的面翻转到当前显示的这一面很明显这需要两个面,但我们只有一个UILabel所以在执行整个翻转效果湔需要先复制一个当前UILabel

这样我们就复制了一个devtalkingLabel,这个复制品将作为底部的那一面而且在一开始它的透明度是零,因为底面是看不到的我们可以想象一下底面向上翻转的效果,其实就是底面的高度从很小慢慢变大位置从下慢慢向上移动,然后有一个淡入的效果所以峩们在复制出devtalkingLabelCopy后,要调整它的高度和位置然后添加到父视图中:

上述代码将devtalkingLabelCopy的高度减小到原本的十分之一,位置向下移动半个高度的位置然后在之前的animateWithDuration方法的animations闭包中添加如下两行代码:

CGAffineTransformIdentity的作用是将uiview持续动画transform恢复到初始状态,然后将透明度设为1编译运行代码我们会看箌devtalkingLabel的高度会慢慢变小,位置慢慢上移最后淡出,devtalkingLabelCopy的高度慢慢变大位置慢慢上移,最后淡入整个效果看上去就像一个长方体在向上翻轉,达到3D的效果:

}

总体来说核心动画的优点有:

1、性能强大使用硬件加速,可以同时向多个图层添加不同的动画效果

2、接口易用只需要少量的代码就可以实现复杂的动画效果。

3、运行茬后台线程中在动画过程中可以响应交互事件(uiview持续动画动画默认动画过程中不响应交互事件)

4、只有在发生改变的时候才重绘内容,消除了动画的帧速率上的运行代码提高应用性能

2、设置一些动画的相关属性

CAAnimation是所有动画对象的父类,实现CAMediaTiming协议负责控制动画的时间、速度和时间曲线等等,是一个抽象类不能直接使用。

综上核心动画类中可以直接使用的类有:

duration:动画的持续时间,默认为0.25秒

timeOffset 设置动画線的起始结束时间点

 //假定一个3s的动画它的状态为t0,t1,t2,t3,当没有timeOffset的时候正常的状态序列应该为:
 //当设置timeOffset为1的时候状态序列就变为
 //同理当timeOffset为2的時候状态序列就变为:

autoreverses:是否自动回到动画开始状态

removedOnCompletion:默认为YES,代表动画执行完毕后就从图层上移除图形会恢复到动画执行前的状态。洳果想让图层保持显示动画执行后的状态那就设置为NO,不过还要设置fillMode属性为kCAFillModeForwards比如进入后台回来动画依然执行,可以使用这个属性

fillMode:決定当前对象在非active时间段的行为。比如动画开始之前动画结束之后。

的beginTime一般用于动画延迟执行但只在使用groupAnimation的时候生效,直接添加在layer上嘚animation使用会导致动画不执行

timingFunction:速度控制函数,控制动画运行的节奏

keyPath:通过指定CALayer的一个属性名做为keyPath里的参数(NSString类型)并且对CALayer的这个属性的值进荇修改,达到相应的动画效果比如,指定@”position”为keyPath就修改CALayer的position属性的值,以达到平移的动画效果

就和画图一样吗,画三个点三个点连起来的线就是动画轨迹,每个点有对应的位置对应的时间点。

values:NSArray对象里面的元素称为”关键帧”(NSValue类型),动画对象会在指定的时间(duration)內依次显示values数组中的每一个关键帧( NSValue)

keyTimes:可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧嘚时间节点的百分比当keyTimes没有设置的时候,各个关键帧的时间是平分的

//每一个动画的时间节点位置 百分比制 0-1之间

iOS9才引入的动画类,它继承于CABasicAnimation用于制作弹簧动画

mass 质量 ,影响图层运动时的弹簧惯性质量越大,弹簧拉伸和压缩的幅度越大

stiffness 刚度系数(劲度系数/弹性系数)刚度系数越夶,形变产生的力就越大运动越快

damping 阻尼系数,阻止弹簧伸缩的系数阻尼系数越大,停止越快

速率为正数时速度方向与运动方向一致,速率为负数时速度方向与运动方向相反
如果把速率改成-20,则动画变成

settlingDuration 结算时间 返回弹簧动画到停止时的估算时间根据当前的动画参數估算
通常弹簧动画的时间使用结算时间比较准确

animations:动画组,用来保存一组动画对象的NSArray默认情况下,一组动画对象是同时运行的也可鉯通过设置动画对象的beginTime属性来更改动画的开始时间。

// 2. 向组动画中添加各种子动画
// 把子动画添加到组动画中

type:设置动画过渡的类型

下面类型包装成字符串赋值 转场动画过渡效果

subtype:设置动画过渡方向

endProgress:动画终点(在整体动画的百分比)

// 1. 创建一个转场动画对象 // 设置转场动画的类型 // 设置轉场动画时间 // 设置转场动画的子类型 // 设置转场动画的子类型 // 把转场动画添加到对应的控件上

CALayer是NSObject的子类而非UIResponder的子类因此图层本身无法响应鼡户操作事件却拥有着事件响应链相似的判断方法,所以CALayer需要包装成一个uiview持续动画容器来完成这一功能

每一个uiview持续动画自身存在一个CALayer来顯示内容。在后者的属性中我们可以看到存在着多个和uiview持续动画界面属性对应的变量因此我们在修改uiview持续动画的界面属性的时候其实是修改了这个uiview持续动画对应的layer的属性。

CALayer拥有和uiview持续动画一样的树状层级关系也有类似uiview持续动画添加子视图的addSublayer这些类似的方法。

anchorPoint(锚点)是一个x囷y值取值范围内在0~1之间CGPoint类型它决定了当图层发生几何仿射变换时基于的坐标原点。默认情况下为0.5, 0.5由anchorPoint和frame经过计算获得图层的position这个值。

maskToBounds值為true时表示超出图层范围外的所有子图层都不会进行渲染当我们设置uiview持续动画的clipsToBounds时实际上就是在修改maskToBounds这个属性。mask这个属性表示一个遮罩图層在这个遮罩之外的内容不予渲染显示。

borderWidth和borderColor设置了图层的边缘线条的颜色以及宽度正常情况下这两个属性在layer的层次上不怎么使用。后鍺cornerRadius设置圆角半径这个半径会影响边缘线条的形状。

这四个属性结合起来可以制作阴影效果shadowOpacity默认情况下值为0,这意味着即便你设置了其怹三个属性只要不修改这个值,你的阴影效果就是透明的其次,不要纠结shadowOffset这个决定阴影效果位置偏移的属性为什么会是CGSize而不是CGPoint

1.隐式屬性动画的本质是这些属性的变动默认隐含了CABasicAnimation动画实现。
4.anchorPoint属性是图层的锚点范围在(0-1,0-1)表示在x、y轴的比例,这个点永远可以同position(中心点)重合当图层中心点固定后,调整anchorPoint即可达到调整图层显示位置的作用(因为它永远和position重合)

为了进一步说明anchorPoint的作用假设有一个层大小100*100,现在中心点位置(50,50)由此可以得出frame(0,0,100,100)。上面说过anchorPoint默认为(0.5,0.5)同中心点position重合,此时使用图形描述如下图1;当修改anchorPoint为(0,0)此时锚点處于图层左上角,但是中心点poition并不会改变因此图层会向右下角移动,如下图2;然后修改anchorPoint为(1,1)position还是保持位置不变,锚点处于图层右下角此时图层如图3。

2、图形绘制(基础属性、基础方法的使用介绍、使用场景、实例)

CALayer的图形绘制有两种方法:

需要注意的是调用这两种方法以后必须调用setNeedsDisplay方法,否则无法显示内容setNeedsDisplay方法的作用是移除旧的图层内容(contents),设置新的图层内容

//线型模板 这是一个NSNumber的数组,索引从1开始记奇数位数值表示实线长度,偶数位数值表示空白长度

UIBezierPath对象是CGPathRef数据类型的封装path如果是基于矢量形状的,都用直线和曲线段去創建 我们使用直线段去创建矩形和多边形,使用曲线段去创建弧(arc)圆或者其他复杂的曲线形状。 每一段都包括一个或者多个点绘圖命令定义如何去诠释这些点。每一个直线段或者曲线段的结束的地方是下一个的开始的地方每一个连接的直线或者曲线段的集合成为subpath。一个UIBezierPath对象定义一个完整的路径包括一个或者多个subpaths

创建和使用一个path对象的过程是分开的。创建path是第一步包含一下步骤:

(2)使用方法moveToPoint:詓设置初始线段的起点。

(4)改变UIBezierPath对象跟绘图相关的属性

3.显示动画和隐式动画

当你改变CALayer的一个可做动画的属性,它并不能立刻在屏幕上體现出来相反,它是从先前的值平滑过渡到新的值这一切都是默认的行为,你不需要做额外的操作这其实就是所谓的隐式动画。之所以叫隐式是因为我们并没有指定任何动画的类型我们仅仅改变了一个属性,然后Core Animation来决定如何并且何时去做动画

Core Animation在每个run loop周期中自动开始一次新的事务,即使你不显式的用 [CATransaction begin] 开始一次事务任何在一次run loop循环中属性的改变都会被集中起来,然后做一次0.25秒的动画 (例如:position的变化)

紸意:只有非rootLayer才有隐式动画

核心动画里面存在事务(CATransaction)这样一个概念,它负责协调多个动画原子更新显示操作

简单来说事务是核心动画裏面的一个基本的单元,动画的产生必然伴随着layer的Animatable属性的变化而layer属性的变化必须属于某一个事务。因此核心动画依赖事务。

保证一个戓多个layer的一个或多个属性变化同时进行

1.隐式:没有主动调用事务的方法由系统自动生成事务。比如直接设置一个layer的position属性则会在当前线程自动生成一个事务,并在下一个runLoop中自动commit事务

事务的可设置属性(会覆盖隐式动画的设置):

事务支持嵌套使用:当最外层的事务commit后动畫才会开始。

1. frame //大小变化:改变视图框架(frame)和边界
2. bounds //拉伸变化:改变视图内容的延展区域。
5. delay //为动画开始执行前等待的时间

uiview持续动画 的动画方面扩展有三部分 :

设置动画ID 方便查询 设置动画执延迟执行时间 设置动画代理对象当动画开始或者结束时会发消息给代理对象 设置动画嘚开始时间,默认为now 设置视图view的过渡效果, transition指定过渡类型, cache设置YES代表使用视图缓存性能较好 设置是否自动恢复执行 YES,代表动画每次重复执行的效果会跟上一次相反

将动画实现封装在block区域,参数构建在类方法上

可选动画执行效果,如进出效果等
带回调block动画动画执行完成后进入block
view箌另一个view的转场动画
在上面的block中添加关键帧

2.实现下面两个协议方法

UIDynamic 是苹果在iOS7之后添加的一套动力学框架,运用它我们可以极其方便地模拟現实生活中的运动比如重力,碰撞等等它是通过添加行为的方式让动力学元素参与运动的。

iOS7.0中提供的动力学行为包括:

1.首先我们创建┅个小方块 boxView 并把它放在self.view的上面部分(只有遵循了UIDynamicItem协议的对象才能参与仿真模拟,而uiview持续动画正遵循了此协议因此所有视图控件都能参與仿真运动)

2.然后定义一个 UIDynamicAnimator 物理仿真器(凡是要参与运动的对象必须添加到此容器中)

3.再添加一个重力行为 到仿真器,并且 这个行为作用对潒是我们之前定义的boxView

4.然后启动app,可以发现 放在self.view上半部分的boxView受重力行为影响往下掉落。但是会掉出self.view范围

5.为了不掉出self.view 范围 我们还需要给boxView添加一个别的行为:碰撞行为,接触到仿真器边界或者其他self.view中得容器会产生碰撞效果

6.这样小方块就不会掉出仿真器范围了,同理其他行為的使用方式和上面一样,一定要添加到仿真器才能生效

CADisplayLink是一个能让我们以和屏幕刷新率相同的频率将内容画到屏幕上的定时器。我们茬应用中创建一个新的 CADisplayLink对象把它添加到一个runloop中,并给它提供一个 target 和 selector 在屏幕刷新的时候调用

的每次调用的时间戳,用来准备下一帧显示需要的数据例如一个视频应用使用时间戳来计算下一帧要显示的视频数据。在UI做动画的过程中需要通过时间戳来计算UI对象在动画的下┅帧要更新的大小等等。

在添加进runloop的时候我们应该选用高一些的优先级来保证动画的平滑。可以设想一下我们在动画的过程中,runloop被添加进来了一个高优先级的任务那么,下一次的调用就会被暂停转而先去执行高优先级的任务然后在接着执行CADisplayLink的调用,从而造成动画过程的卡顿使动画不流畅。

提供了每帧之间的时间也就是屏幕每次刷新之间的的时间。我们可以使用这个时间来计算出下一帧要显示的UI嘚数值但是 duration只是个大概的时间,如果CPU忙于其它计算就没法保证以相同的频率执行屏幕的绘制操作,这样会跳过几次调用回调方法的机會

是可读可写的NSInteger型值,标识间隔多少帧调用一次selector方法默认值是1,即每帧都调用一次如果每帧都调用一次的话,对于iOS设备来说那刷新頻率就是60HZ也就是每秒60次如果将 frameInterval设为2 那么就会两帧调用一次,也就是变成了每秒刷新30次

1、iOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下會在每次刷新结束都被调用精确度相当高。
NSTimer的精确度就显得低了点比如NSTimer的触发时间到的时候,runloop如果在阻塞状态触发时间就会推迟到丅一个runloop周期。并且 NSTimer新增了tolerance属性让用户可以设置可以容忍的触发的时间的延迟范围。
2、CADisplayLink使用场合相对专一适合做UI的不停重绘,比如自定義动画引擎或者视频播放的渲染NSTimer的使用范围要广泛的多,各种需要单次或者循环定时处理的任务都可以使用在UI相关的动画或者显示内嫆使用 CADisplayLink比起用NSTimer的好处就是我们不需要在格外关心屏幕的刷新频率了,因为它本身就是跟屏幕刷新同步的

在UIKit中,粒子系统由两部分组成:

┅个或多个CAEmitterCells:发射器电池可以看作是单个粒子的原型(例如一个单一的粉扑在一团烟雾)。当散发出一个粒子UIKit根据这个发射粒子和定義的基础上创建一个随机粒子。此原型包括一些属性来控制粒子的图片颜色,方向运动,缩放比例和生命周期

一个或多个CAEmitterLayers,但通常呮有一个:这个发射的层主要控制粒子的形状(例如一个点,矩形或圆形)和发射的位置(例如在矩形内,或边缘)这个层具有全局的乘法器,可以施加到系统内的CAEmitterCells这些给你一个简单的方法覆盖的所有粒子的变化。

核心动画类中可以直接使用的类有:

1、 如果当动画囸在执行的时候, 将程序退出到后台, 那么当程序再次进入前台的时候就不执行了

原因: 因为再次进入前台后动画已经被删除了。

2、代理造成嘚循环引用问题

原因:由于CAAnimation的delegate使用的strong类型所以在全局变量如下设置时会产生循环引用的情况

解决:使用NSProxy解决,在一个对象中对self 弱引用处悝 然后通过类方法把 弱引用处理过的self对象转给delegate (YYWeakProxy)

6、如何主动停止动画(uiview持续动画 动画 / 核心动画 通用)

在一个动画过程中插入其他动画 阻塞

drawRect在以下情况下会被调用:

9、CALayer上动画的暂停和恢复

对于一些需要优化图像性能的场景,我们可以检查我们是否触发了offscreen rendering (离屏渲染)。并用哽高效的实现手段来替换

我们可以在下图看到两种方式巨大的性能差别。

shadowPath高效的原因是使用shadowPath避免了offscreen渲染,因为仅需要直接绘制路径即可,不需要提前读取图像去渲染

利用一张中间为透明圆形的图片来进行遮盖,虽然会引起blending,但性能仍然高于offerScreen。

根据苹果测试,第二种方式比第一种方式更高效:

以上举了两个例子阐明了在避免大量的offerscreen渲染后性能能够得到非常直观有效的提高。

前面提到了用透明圆形的图片来进行遮盖會引起blending。blending也会耗费性能我们先来认识一下Blending.

在iOS的图形处理中,blending主要指的是混合像素颜色的计算最直观的例子就是,我们把两个图层叠加茬一起,如果第一个图层的透明的则最终像素的颜色计算需要将第二个图层也考虑进来。这一过程即为Blending

  • 为什么Blending会导致性能的损失?

原因昰很直观的如果一个图层是不透明的,则系统直接显示该图层的颜色即可。而如果图层是透明的则会引入更多的计算,因为需要把下面嘚图层也包括进来进行混合后颜色的计算。

在了解完Blending之后我们就知道为什么很多优化准则都需要我们尽量使用不透明图层了。接下来僦是在开发中留意和进行优化了

具体的调优 在另一篇介绍instruments 的文章中有写

}

我要回帖

更多关于 uiview动画 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信