iOS核心动画高级技巧(中)

隐式动画

Core Animation基于一个假设,说屏幕上的任何东西都可以做动画。动画并不需要你在Core Animation中手动打开,相反需要明确地关闭,否则它会一直存在,这其实就是所谓的隐式动画

事务

实际上动画执行的时间取决于当前的事务设置,动画类型取决于图层行为事务是通过CATransaction类来做管理。CATransaction没有属性或者实例方法,并且也不能用+alloc和-init方法创建它。但是可以用+begin+commit分别来入栈或者出栈。

任何可以做动画的图层属性都会被添加到栈顶的事务,可以通过+setAnimationDuration:方法设置当前事务的动画时间,或者通过+animationDuration方法来获取值(默认0.25秒)。

Core Animation在每个run loop周期中自动开始一次新的事务(run loop是iOS负责收集用户输入,处理定时器或者网络事件并且重新绘制屏幕的东西),即使你不显式的用[CATransaction begin]开始一次事务,任何在一次run loop循环中属性的改变都会被集中起来,然后做一次0.25秒的动画。

CATransaction.begin()
CATransaction.setAnimationDuration(1.0)

let red:CGFloat=CGFloat(rand()) / CGFloat(INT_MAX)
let green:CGFloat=CGFloat(rand()) / CGFloat(INT_MAX)
let blue:CGFloat=CGFloat(rand()) / CGFloat(INT_MAX)
self.colorLayer.backgroundColor=UIColor(red: red, green: green, blue: blue, alpha: 1.0).CGColor 

CATransaction.commit()
完成块

基于UIView的block的动画允许你在动画结束的时候提供一个完成的动作。CATranscation接口提供的+setCompletionBlock:方法也有同样的功能。

CATransaction.setCompletionBlock { () -> Void in
var transform:CGAffineTransform=self.colorLayer.affineTransform()
transform=CGAffineTransformRotate(transform,CGFloat(M_PI_2)) 
self.colorLayer.setAffineTransform(transform) }
图层行为

我们把改变属性时CALayer自动应用的动画称作行为,当CALayer的属性被修改时候,它会调用-actionForKey:方法,传递属性的名称。其步骤为:

  • 图层首先检测它是否有委托,并且是否实现CALayerDelegate协议指定的-actionForLayer:forKey方法。如果有,直接调用并返回结果。
  • 如果没有委托,或者委托没有实现-actionForLayer:forKey方法,图层接着检查包含属性名称对应行为映射的actions字典。
  • 如果actions字典没有包含对应的属性,那么图层接着在它的style字典接着搜索属性名。
  • 最后,如果在style里面也找不到对应的行为,那么图层将会直接调用定义了每个属性的标准行为的-defaultActionForKey:方法。

返回nil并不是禁用隐式动画的唯一方法,CATransaction有个方法+setDisableActions:,可以用来对所有属性打开或者关闭隐式动画。

 CATransaction.setDisableActions(true)

行为通常是一个被Core Animation隐式调用的显式动画对象。这里我们使用的是一个实现了CATransaction的实例,叫做推进过渡

let transition=CATransition() 
transition.type=kCATransitionPush
transition.subtype=kCATransitionFromLeft 
self.colorLayer.actions=["backgroundColor":transition]
呈现与模型

每个图层属性的显示值都被存储在一个叫做呈现图层的独立图层当中,他可以通过-presentationLayer方法来访问。这个呈现图层实际上是模型图层的复制,但是它的属性值代表了在任何指定时刻当前外观效果。
在什么情况下呈现图层会变得很有用,一个是同步动画,一个是处理用户交互

  • 如果你在实现一个基于定时器的动画,而不仅仅是基于事务的动画,这个时候准确地知道在某一时刻图层显示在什么位置就会对正确摆放图层很有用了。
  • 如果你想让你做动画的图层响应用户输入,你可以使用-hitTest:方法来判断指定图层是否被触摸,这时候对呈现图层而不是模型图层调用-hitTest:会显得更有意义,因为呈现图层代表了用户当前看到的图层位置,而不是当前动画结束之后的位置。

显式动画

属性动画

关键帧动画

let bezierPath=UIBezierPath() 
bezierPath.moveToPoint(CGPointMake(0, 150))
bezierPath.addCurveToPoint(CGPointMake(300, 150), 
controlPoint1: CGPointMake(75, 0), 
controlPoint2: CGPointMake(225, 300))  

let pathLayer=CAShapeLayer() 
pathLayer.path=bezierPath.CGPath 
pathLayer.fillColor=UIColor.clearColor().CGColor 
pathLayer.strokeColor=UIColor.redColor().CGColor 
pathLayer.lineWidth=3.0 
self.containerView.layer.addSublayer(pathLayer)  

let shipLayer=CALayer() 
shipLayer.frame=CGRectMake(0, 0, 64, 64) 
shipLayer.position=CGPointMake(0, 150) 
shipLayer.contents=UIImage(named: "logo")!.CGImage 
self.containerView.layer.addSublayer(shipLayer)  

let animation=CAKeyframeAnimation() 
animation.keyPath="position" 
animation.duration=4.0 
animation.path=bezierPath.CGPath 
animation.rotationMode = kCAAnimationRotateAuto//图层将会根据曲线的切线自动旋转 
shipLayer.addAnimation(animation, forKey: nil)

虚拟属性

let animation=CABasicAnimation() 
animation.keyPath="transform.rotation" 
animation.duration=2.0 
animation.byValue=CGFloat(M_PI_2*2) 
shipLayer.addAnimation(animation, forKey: nil)

使用transform.rotation而不是transform的好处是:

  • 我们可以不通过关键帧一步旋转多于180度的动画;
  • 可以用相对值而不是绝对值旋转(设置byValue而不是toValue);
  • 可以不用创建CATransform3D,而是使用一个简单的数值来指定角度;
  • 不会和transform.position或者transform.scale冲突(同样是使用关键路径来做独立的动画属性)

transform.rotation属性有一个奇怪的问题是它其实并不存在。这是因为CATransform3D并不是一个对象,它实际上是一个结构体,也没有符合KVC相关属性,transform.rotation实际上是一个CALayer用于处理动画变换的虚拟属性

动画组

利用CAAnimationGroup可以把动画组合在一起,组成动画组。

let bezierPath=UIBezierPath()
bezierPath.moveToPoint(CGPointMake(50, 250))
bezierPath.addCurveToPoint(CGPointMake(300, 150), 
controlPoint1: CGPointMake(75, 0), 
controlPoint2: CGPointMake(225, 300))

let pathLayer=CAShapeLayer()
pathLayer.path=bezierPath.CGPath
pathLayer.fillColor=UIColor.clearColor().CGColor
pathLayer.strokeColor=UIColor.redColor().CGColor
pathLayer.lineWidth=3.0
self.view.layer.addSublayer(pathLayer) 

let colorLayer=CALayer()
colorLayer.frame=CGRectMake(50, 250, 64, 64)
colorLayer.position=CGPointMake(50, 250) 
colorLayer.backgroundColor=UIColor.greenColor().CGColor
self.view.layer.addSublayer(colorLayer) 

let animation1=CAKeyframeAnimation()
animation1.keyPath="position"
animation1.path=bezierPath.CGPath
animation1.rotationMode=kCAAnimationRotateAuto 

let animation2=CABasicAnimation()
animation2.keyPath="backgroundColor"
animation2.toValue=UIColor.redColor().CGColor 

let groupAnimation=CAAnimationGroup()
groupAnimation.animations=[animation1,animation2]
groupAnimation.duration=4.0 

colorLayer.addAnimation(groupAnimation, forKey: nil)
过渡

使用CATransition创建一个过渡动画,它有一个typesubtype来标识变换效果。type有如下四种类型:

  • kCATransitionFade:平滑的淡入淡出效果
  • kCATransitionMoveIn:顶部滑动进入
  • kCATransitionPush:新图层一侧滑动进来,旧图层从另一侧推出去
  • kCATransitionReveal:把原始的图层滑动出去来显示新的外观

subtype控制它们的滑入方向:

  • kCATransitionFromRight
  • kCATransitionFromLeft
  • kCATransitionFromTop
  • kCATransitionFromBottom

自定义动画

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, true, 0.0)
self.view.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let coverImage:UIImage=UIGraphicsGetImageFromCurrentImageContext()
let coverView=UIImageView(image: coverImage)
coverView.frame=self.view.bounds
self.view.addSubview(coverView)
let red:CGFloat=CGFloat(rand()) / CGFloat(INT_MAX)
let green:CGFloat=CGFloat(rand()) / CGFloat(INT_MAX)
let blue:CGFloat=CGFloat(rand()) / CGFloat(INT_MAX)
self.view.backgroundColor=UIColor(red: red, green: green, blue: blue, alpha: 1.0) 

UIView.animateWithDuration(1.0, animations: { () -> Void in
var transform:CGAffineTransform=CGAffineTransformMakeScale(0.01, 0.01) 
transform=CGAffineTransformRotate(transform,CGFloat(M_PI_2))
coverView.transform=transform
coverView.alpha=0.0
}) { (finished) -> Void in
coverView.removeFromSuperview()
}

图层时间

CAMediaTiming协议

CAMediaTiming协议
定义了在一段动画内用来控制逝去时间的属性的集合,CALayer和CAAnimation都实现了这个协议,所以时间可以被任意基于一个图层或者一段动画的类控制。
CAMediaTiming除了有duration属性还有另外一个属性叫repeatCount,代表动画重复的迭代次数。
创建重复动画的另外一种方式是使用repeatDuration属性,它让动画重复一个指定时间,而不是指定次数。设置一个叫做autoreverses的属性(BOOL类型)在每次间隔交替循环过程中自动回放。
注意:repeatCount和repeatDuration可能会相互冲突,所以你只要对其中一个指定非零值。

相对时间:
时间都是相对的,每个动画都有它自己的描述的时间,可以独立地加速,延时或者偏移。
beginTime指定了动画开始之前的延迟时间。这里的延迟从动画添加到可见图层的那一刻开始测量,默认是0。
speed是一个时间的倍数,默认1.0,减少它会减慢图层/动画的时间,增加它会加快速度。
timeOffsetbeginTime类似,但是和增加beginTime导致的延迟动画不同,增加timeOffset只是让动画快进到某一点,例如,对于一个持续1秒的动画来说,设置timeOffset为0.5意味着动画将从一半的地方开始。
注:和beginTime不同的是,timeOffset并不受speed的影响。

fillMode:保持动画开始之前那一帧,或者动画结束之后的那一帧。这就是所谓的填充,因为动画开始和结束的值用来填充开始之前和结束之后的时间。
这就是被CAMediaTiming的fillMode来控制,有如下四种常量:

  • kCAFillModeForwards
  • kCAfillModeBackwards
  • kCAFillModeBoth
  • kCAFillModeRemoves

未完待续......

转载于:https://my.oschina.net/hejunbinlan/blog/700247

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言用于封装代码的单元,可以实现代码的复用和模块化。C语言定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言用于存储同类型数据的结构,可以通过索引访问和修改数组的元素。字符串是C语言用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值