iOS动画学习笔记2 Video Tutorial iOS Animation with Swift - Ray Wenderlich

来源:互联网 发布:问卷调查表数据库设计 编辑:程序博客网 时间:2024/05/16 09:39

接着上次的笔记,后面的课程教大家实现了这样一个登录界面,好看又好玩,交互性很强,balabala……给大家看下⬇️
登录页面
仔细看下,整个界面总体来说用到了4个动画效果:
1.”Bahama Login”heading、username文本框、password文本框的右滑出现
2.”Log In”button向上弹出,点击后,变宽变色并下滑
3.登录状态提示框翻转出现,状态更换后,右滑消失,在未登录成功”failed”时,左右旋转
4.背景里一直向右飘的朵朵白云(这个你发现了没~)

首先说明一点知识,我们需要在viewWillAppear(也就是控制器马上要显示到屏幕上时)中设定控件的起始位置,然后在viewDidAppear(当控制器已经显示在屏幕上时)中实现动画效果。

1.heading、username、password 的右滑出现,其中heading的动画因为没有延迟,所以无需在viewWillAppear中设定起始位置,通过CABasicAnimation函数设定起始值、终点值、动画时长,CABasicAnimation一次只能更改控件的一个属性,要想更改多个属性,可以用CAAnimationGroups这个方法。

//给heading加CALayer动画        let flyRight = CABasicAnimation(keyPath: "position.x")        flyRight.fromValue = -view.bounds.size.width/2        flyRight.toValue = view.bounds.size.width/2        flyRight.duration = 0.5        heading.layer.addAnimation(flyRight, forKey: nil)

username、password的动画因为有延迟,所以需要在viewWillAppear中设定起始位置:

override func viewWillAppear(animated: Bool) {        super.viewWillAppear(animated)        //username,password的layer动画有延迟,所以需要规定起始位置        username.center.x -= view.bounds.width        password.center.x -= view.bounds.width    }

添加动画时,可以直接用刚刚添加给heading的flyRight动画:

    override func viewDidAppear(animated: Bool) {        super.viewDidAppear(animated)        //给heading加CALayer动画        let flyRight = CABasicAnimation(keyPath: "position.x")        flyRight.fromValue = -view.bounds.size.width/2        flyRight.toValue = view.bounds.size.width/2        flyRight.duration = 0.5        heading.layer.addAnimation(flyRight, forKey: nil)//        flyRight.removedOnCompletion = false//        flyRight.fillMode = kCAFillModeForwards        flyRight.delegate = self        flyRight.setValue("form", forKey: "name")        flyRight.setValue(username.layer, forKey: "layer")        flyRight.beginTime = CACurrentMediaTime() + 0.3        username.layer.addAnimation(flyRight, forKey: nil)        flyRight.setValue(password.layer, forKey: "layer")        flyRight.beginTime = CACurrentMediaTime() + 0.4        password.layer.addAnimation(flyRight, forKey: nil)    }

需要设定动画的beginTime属性值来到达延迟的效果。运行后发现,username和password在动画结束后消失了,需要设定动画的removedOnCompletion为false,也就是动画结束后不在屏幕上移除,并设定fillMode为出现在屏幕前方。
但是这样设置,虽然后面username、password在动画结束后虽然没有消失,但是,不能获取到焦点,文本框不能点击,只是出现在screen上,这是因为Layer动画关注的是控件画出来的过程,不能像UIView一样响应事件。这时就需要设置动画的代理,在结束动画后,将控件的属性更新为动画结束后的位置。
动画的代理方法很简单,只有两个,分别是animationDidStart和animationDidStop。

override func animationDidStop(anim: CAAnimation, finished flag: Bool) {        let nameValue = anim.valueForKey("name") as? String        if let name = nameValue {            if name == "form"{                let layer: CALayer = anim.valueForKey("layer")! as! CALayer                layer.position.x = view.bounds.size.width/2                anim.setValue(nil, forKey: "layer")            }        }    }

动画主要通过键值对的方式存储和取出对应的属性,在移除时可以直接使用Layer的removeAnimationForKey这个方法,十分方便。

2.“Log In”button向上弹出,点击后,变宽变色并下滑,这里需要在viewWillAppear中设定起始位置并将透明度改为0,让它先“消失”:

override func viewWillAppear(animated: Bool) {        super.viewWillAppear(animated)        loginButton.center.y += 30.0        loginButton.alpha = 0.0    }

类似于“弹簧”效果的实现:

UIView.animateWithDuration(0.5, delay: 0.5, usingSpringWithDamping: 0.35, initialSpringVelocity: 0, options: .CurveEaseIn, animations: { () -> Void in            self.loginButton.center.y -= 30.0            self.loginButton.alpha = 1.0}, completion: nil)

其中,usingSpringWithDamping的值表示“弹力“,在0到1之间,越接近0弹力越大; initialSpringVelocity的值表示弹簧初始速度。
点击后,loginButton向下飞,并变宽变色,loginButton上方出现显示登录信息的标签栏status,细心的童鞋可能还会发现loginButton上还有了一个环形进度条spinner开始旋转,代码如下:

UIView.animateWithDuration(1.5, delay: 0.0, usingSpringWithDamping: 0.2, initialSpringVelocity: 20, options: [], animations: { () -> Void in            let b = self.loginButton.bounds            self.loginButton.bounds = CGRect(x: b.origin.x - 20, y: b.origin.y, width: b.size.width + 80, height: b.size.height)            },completion: nil)        UIView.animateWithDuration(0.33, delay: 0.0, options: .CurveEaseOut, animations: { () -> Void in            if self.status.hidden{                self.loginButton.center.y += 60            }            self.spinner.center = CGPoint(x: 40, y: self.loginButton.frame.size.height/2)            self.spinner.alpha = 1.0            self.loginButton.backgroundColor = UIColor(red: 217.0/255.0, green: 211.0/255.0, blue: 114.0/255.0, alpha: 1.0)            }, completion: nil)

3.登录状态提示框翻转出现,状态更换后,右滑消失,在未登录成功”failed”时,左右旋转。在showMessages这个方法显示登录信息标签栏,通过index标记不同信息text。

func showMessages(index index:Int){        let labelOriginalFrame = self.status.frame        UIView.animateWithDuration(0.33, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0, options: [], animations: { () -> Void in            //oldLabel向右滑动            self.status.center.x += self.view.frame.size.width            }, completion: {(finished: Bool) -> Void in                //初始化newLabel                self.status.hidden = true                self.status.frame = labelOriginalFrame                self.label.text = self.messages[index]                //newLabel翻转出现                UIView.transitionWithView(self.status, duration: 0.33, options: .TransitionFlipFromBottom, animations: { () -> Void in                    self.status.hidden = false                    }, completion: {(finished: Bool) -> Void in                        //如果显示完所以状态,则重置loginButton,让loginButton变短变色;若没有,则延迟调用(这个函数的定义第一篇笔记中提到过)自身显示下一条状态信息                        delay(seconds: 1.0, completion: { () -> () in                            if index < self.messages.count - 1 {                                self.showMessages(index: index + 1)                            }else{                                //重置loginButton                            }                        })                })        })    }

这个动画效果的切换主要是旧状态栏向右滑,结束时,新的状态栏翻转出现,这个动画结束时在检查状态栏是否都展示完,没有则调用自身,展示新的状态栏;展示完了则重置loginButton回到之前状态。
在未登录成功”failed”时,状态栏左右旋转,十分好玩,让我们看看是怎么实现的:

let bounce = CAKeyframeAnimation(keyPath: "transform.rotation.z")            bounce.values = [0.0, -M_PI_4/2, 0.0, M_PI_4/2, 0.0]            bounce.keyTimes = [0.0, 0.25, 0.5, 0.75, 1.0]            bounce.additive = true            bounce.repeatCount = 4            status.layer.addAnimation(bounce, forKey: "wobble")

主要用到CAKeyframeAnimation方法更改控件的transform.rotation.z属性,values设定旋转角度,keyTimes设定旋转每个角度的时长,additive为true时,动画属性值会叠加在当前的present层中的keyPath,repeatCount表示动画执行次数。

4.背景里一直向右飘的朵朵白云,方法很简单,但是效果感觉还不错:

func animateCloud(cloud: UIImageView) {        let cloudSpeed = 20.0 / Double(view.frame.size.width)        let duration: NSTimeInterval = Double(view.frame.size.width - cloud.frame.origin.x) * cloudSpeed        UIView.animateWithDuration(duration, delay: 0.0, options: .CurveLinear, animations: { () -> Void in            cloud.frame.origin.x = self.view.bounds.size.width            }, completion: {(finished: Bool) -> Void in                cloud.frame.origin.x = -self.cloud1.frame.size.width                self.animateCloud(cloud)        })    }

比较特别的是,在设定动画时长的时候,用到这样一个公式
这里写图片描述

这样设定时长,就可以使云朵缓缓向右飘去了……

0 0
原创粉丝点击