iOS Animation 初窥

论动画在App中的重要性

引言

  • 一款App是否足够吸引人一方面是需要丰富的内容,另一方面就是要足够人性化的交互,还有一些锦上添花的动画效果,在这里我们讨论一下关于Animation的基本实现,推荐大家试用FaceBook Paper,里面包含了大量的非原生动画效果,Paper团队甚至封装了相应的开源库Pop,让开发者接入自定义动画动画也十分简便。动画的接入要适当,否则用户面对眼花缭乱的动画效果,都会无从下手。这里有个基于Pop的Demo

  • 当然导入一个复杂的第三方库可能有些小题大做,所以我们开始从最基本的创作Animation开始

  • 在iOS设备上画动画可以分为以下几种方式,最直接的时在UIView上实现动画,假如实现效果复杂可以在Layer下绘制,此外iOS7还推出了UIDynamicAnimator,实现类似游戏中的诸多动画效果

  • 动画不是那种天花乱坠式,而是在一些细节之处也添加动画,例如在view之间的约束,在设备旋转过程中调整对应动画,viewController之间的切换也是可以自定义transitioning

UIView Animations

UIView可以设置动画的属性:

属性 改变
frame & bounds & center 改变View的位置及自身大小
transform 改变缩放scale,旋转角度rotate(3D效果需要用Core Animation)
alpha 改变透明度
backgroundColor 改其背景色

最直接的做法

//基本
UIView.animateWithDuration(0.5, animations: {
  self.yourView.bounds.size.witdh += 70.0
  self.yourView.backgroundColor = UIColor.greenColor()
  self.yourView.alpha = 0.5
})

//View和View之间的过渡
UIView.transitionWithView(containerView, duration: 0.2, options: .TransitionFlipFromLeft, animations: { _ in fromView.removeFromSuperview(); containerView.addSubview(toView) }, completion: nil)

//入门Option,delay,option自由选择
UIView.animateWithDuration(0.5, delay: 0.4, options: .Repeat, animations:{
    self.yourView.center.x + = 30.0
},completion: nil)


//进阶,Spring属性可以调整动画的弹簧效果
UIView.animateWithDuration(1.5, delay: 0.0, usingSpringWithDamping: 0.2, initialSpringVelocity: 0.0, options: nil, animations: {
self.loginButton.bounds.size.width += 80.0 
label的文字可以进行一些过渡效果
}, completion: nil)


//高阶,复杂动画组合之KeyFrame
UIView.animateKeyframesWithDuration(1.5, delay: 0.0, options: nil, animations: {
//添加KeyFrames,options中可以选择不同的限制

//1
UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.25, animations: {
self.planeImage.center.x += 80.0
self.planeImage.center.y -= 10.0 
})

//2
UIView.addKeyframeWithRelativeStartTime(0.1, relativeDuration: 0.4) { self.planeImage.transform = CGAffineTransformMakeRotation(CGFloat(-
M_PI_4/2)) }

}, completion: nil)

需要注意的是动画一旦开始就没有办法暂停

Auto Layout

为AutoLayout Aonstraints创建动画的首要条件就是,你要先用了AutoLayout

动画的创建方式也类似

//对已有constant作出对应修改操作 or 创建新的contsant
UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.4, initialSpringVelocity: 10.0, options: .CurveEaseIn, animations: {
self.view.layoutIfNeeded() }, completion: nil)

其中的layoutIfNeed()十分关键,因为这样UIKit才会知道你修改了layout

Layer Animation

如果说View是高度定制化的给你简单接口的就像这样

那CALayer就是这样

Layer的强大之处是可以设置更多的属性,实现3D效果,添加mask,添加shadow,并且这一切都是建立在直接调用GPU来达到快速相应,一切都非常简便,其实每个View都有Layer,我们在Layer层面做的修改也可以展现在View上

属性 作用
size & position 改变layer的位置及自身大小
transform 改2D,3D情况下的现实效果
shadow 改变阴影
border 边框效果
opacity 改其透明度
//记得引入QuartzCore
//基本
let ownStyle = CABasicAnimation(keyPath:"position.x")
ownStyle.fromValue = -view.bounds.size.width/2
ownStyle.toValue = view,bounds.size.width/2
ownStyle.duration = 0.5
yourView.layer.addAnimation(ownStyle, forKey: nil)
//入门,动画之间存在时间差,我们可以设置fillMode和beginTime来实现特定效果
ownStyle.beginTime = CACurrentMediaTime() + 0.3
ownStyle.fillMode = KCAFillModeRemoved //default
//kCAFillMode主要作用就是控制你动画在开始和结束时候的一些效果

//进阶 CAAnimation delegate pattern
func animationDidStop & animationDidStart
//与block中的相类似,你也可以利用KVC特性设置相应内容
ownStyle.setValue(yourView.layer, forKey:"layer")
ownStyle.setValue("name", forKey:"form")
override func animationStop(anima: CAAnimation!, finished flag: Bool) {
    if let name = ownStyle.valueForKey("form") as? String {
        if name = "form" {
            //add new animation and add it to the layer
        }   
    }
}

//addAnimation中的Key作用,标示动画,在恰当的时候移除对应动画,而不是移除动画效果本身


//高阶,AnimationGroup
let groupAnimation = CAAnimationGroup()
let oneAnimation = CABasicAnimation(keyPath:"transform.scale")
//blablabla

let twoAnimation = CABasicAnimation(keyPath:"opacity")
//detail set for twoAnimation

//sey timingFunction
groupAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)

//这么只能一起做动画,这里内部没有时间顺序
groupAnimation.animations = [oneAnimation, twoAnimation] 
yourView.layer.addAnimation(groupAnimation, forKey: nil)

//CAKeyFrame,关键帧动画Layer级别效果
let wobble = CAKeyframeAnimation(keyPath: "transform.rotation") wobble.duration = 0.25
wobble.repeatCount = 4

//比View的keyFrame设置方便多了
//values与keyTimes一一对应
wobble.values = [0.0, -M_PI_4/4, 0.0, M_PI_4/4, 0.0]
wobble.keyTimes = [0.0, 0.25, 0.5, 0.75, 1.0] heading.layer.addAnimation(wobble, forKey: nil)

//不过坑爹的是这样,比如CGPoint,CGSize,CGRect,CATransform3D,都要解包
let move = CABasicAnimation(keyPath: "position")
move.duration = 1.0
move.fromValue = NSValue(CGPoint:CGPoint(x:100.0, y:100.0))
move.toValue = NSValue(CGPoint:CGPoint(x:200.0, y:200.0))

有木有发现现在很多App中用户头像都是圆形的QQ的是,微博个人主页,instagram,Path等等,这里还涉及到好多设计心理学的东西这里给个链接圆形头像为何流行起来--知乎

废话不多说直接上代码吧,so easy,简单说来就是加一个mask,可这好像和动画没有什么关系,听我慢慢道来

//1
_imageView.frame = CGRectMake(0, 0, iconWH, iconWH);
_imageView.layer.cornerRadius = _imageView.frame.size.width / 2;
_imageView.clipsToBounds = YES;
_imageView.layer.borderWidth = 2.0f;
_imageView.layer.borderColor = [UIColor whiteColor].CGColor;

//2
 let photoLayer = CALayer()
 let circleLayer = CAShapeLayer()
 let maskLayer = CAShapeLayer()

  override func didMoveToWindow() {
    layer.addSublayer(photoLayer)
    photoLayer.mask = maskLayer
    layer.addSublayer(circleLayer)
    addSubview(label)
  }

  //设置image的Frame
  photoLayer.frame = CGRect(
      x: (bounds.size.width - image.size.width + lineWidth)/2,
      y: (bounds.size.height - image.size.height - lineWidth)/2,
      width: image.size.width,
      height: image.size.height)
      
  //画圆,用UIBezierPath
  circleLayer.path = UIBezierPath(ovalInRect: bounds).CGPath
    circleLayer.strokeColor = UIColor.whiteColor().CGColor
    circleLayer.lineWidth = lineWidth
    circleLayer.fillColor = UIColor.clearColor().CGColor
    
  //设置对应的path
    maskLayer.path = circleLayer.path
    maskLayer.position = CGPoint(x: 0.0, y: 10.0)

三者对应关系circleLayer在顶,maskLayer在中,photoLayer在底

如果你要实现这个imageView如在撞击墙壁时,mask产生变化,变成方形,这样一个碰撞式的动画还是很带感的

let maskLayer = CAShapeLayer()
imageView.mask = maskLayer

let squarePath = UIBezierPath(rect: bounds).CGPath
let morph = CABasicAnimation(keyPath: "path")
morph.duration = 0.25
morph.fromValue = circleLayer.path
morph.toValue = squarePath

circleLayer.addAnimation(morph, forKey: nil)
maskLayer.addAnimation(morph, forKey: nil)

平面效果是否不够酷炫,那么来足够眼前一亮的的

3D效果,这里要扯点美术内容了,透视法

目前的屏幕还是2D平面,也无法实现所谓全息影像

那么在2D屏幕下的3D就需要透过视觉差来投影出来3D效果

当相机距离很小时候拉伸效果明显,后者距离很大

    var identity = CATransform3DIdentity
    //m34啥意思,简单说来就是你看屏幕视角的远近,这里是指近大远小,-1.0/1000啥概念,这里1000是指相机距离,距离越小,近大远效果越明显
    identity.m34 = -1.0/1000
    
    //percent在这里是指你在移动当前View时候frame.orgin.x与一固定值如width之间的比例,这样view的移动就产生相应不同程度的过渡效果
    let remainingPercent = 1.0 - percent
    let angle = remainingPercent * CGFloat(-M_PI_2)
    //这里是沿着y轴旋转,这里不得不说一下iOS中坐标系是左手坐标系
    
    let rotationTransform = CATransform3DRotate(identity, angle, 0.0, 1.0, 0.0)
    let translationTransform = CATransform3DMakeTranslation(menuWidth * percent, 0, 0)
    //还有诸如  CATransform3DTranslate,CATransform3DScale相关设置都可以尝试
    menuButton.imageView.layer.transform =  CATransform3DConcat(rotationTransform, translationTransform)

左边是左手坐标系,右边是我们惯用的右手坐标系,两者区别在于z轴的方向,iOS是左手系

view的转动效果如下,x,y,z轴你可以设置根据相应的轴产生不同动画以及组合动画


致此,iOS的动画初窥到此为止,发现具体到动画中矩阵转换还是有点搞不清楚,后续还会有更多关于iOS Animation的内容。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥ios动画全貌。在这里你可以看...
    每天刷两次牙阅读 8,461评论 6 30
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,019评论 4 62
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看...
    F麦子阅读 5,092评论 5 13
  • 今天打算执行为期一个月的进餐减半计划。今天的日期也比较好记,2 月 22 号,拿来做二分之一的意思,不是两倍的意思...
    小王加油啊阅读 205评论 0 0
  • 十里桃花吐芬芳 一朵不慎落面上 惊喜怡然入花廊 月牙儿不禁挂眉梢 芳草落花吻纤足 融融春光润鬓霜 吾意误认是晨晓 ...
    恬淡人生888阅读 124评论 0 1