2016年1月

车小弟模仿

需要注意的是几个动画对象的同时使用
//
//  ViewController.swift
//  车小弟
//
//  Created by admin on 16/1/28.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var image: UIImageView!
    override func viewDidLoad() {
        super.viewDidLoad()
        for var i = 1;i < 4;i++
        {
            let button = UIButton(type: UIButtonType.Custom)
//            button.frame = CGRectMake(-153, -153, 612, 612)
            // 勾选了use autolayout这里就显示不正常,就需要用上面的CGRect,但是取消之后再勾选就又正常了。。。。
            button.frame = self.image.bounds
            button.setImage(UIImage(imageLiteral: "circle\(i)"), forState: UIControlState.Normal)
            self.image.addSubview(button)
        }
        let image = UIImage(imageLiteral: "home_btn_dealer_had_bind")
        let button = UIButton(type: UIButtonType.Custom)
        button.bounds = CGRectMake(0, 0, image.size.width, image.size.height)
        button.center = self.image.center
        button.setImage(image, forState: UIControlState.Normal)
        button.addTarget(self, action: "changeImage", forControlEvents: UIControlEvents.TouchDown)
        self.view.addSubview(button)
    }
    func changeImage()
    {
        if self.image.layer.animationForKey("changeImage") != nil
        {
            return
        }
        let animationGroup = CAAnimationGroup()
        // 透明度
        let fade = CABasicAnimation(keyPath: "opacity")
        // 缩放
        let scale = CAKeyframeAnimation(keyPath: "transform.scale")
        // 旋转
        let rotation = CABasicAnimation(keyPath: "transform.rotation")
        // 做不同的操作
        if self.image.layer.opacity == 0
        {
            self.image.layer.opacity = 1
            // 设置路径
            scale.values = [0,1.2,1.0]
            rotation.fromValue = -CGFloat(M_PI * 0.25)
            rotation.toValue = 0
        }
        else
        {
            self.image.layer.opacity = 0
            scale.values = [1.0,1.2,0]
            rotation.fromValue = 0
            rotation.toValue = -CGFloat(M_PI * 0.25)
        }
        // 添加进入分组
        animationGroup.animations = [fade,scale,rotation]
        animationGroup.duration = 1
        self.image.layer.addAnimation(animationGroup, forKey: "changeImage")
    }
}

图片浏览器,使用动画效果实现 CATransition

//
//  ViewController.swift
//  图片浏览器_核心动画
//
//  Created by admin on 16/1/28.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var image: UIImageView!
    lazy var images:[UIImage] = {
        var images:[UIImage] = []
        for var i = 1;i <= 9;i++
        {
            images.append(UIImage(imageLiteral: "\(i)"))
        }
        return images
    }()
    override func viewDidLoad() {
        super.viewDidLoad()
        let tap = UITapGestureRecognizer(target: self, action: "switchImage:")
        self.image.addGestureRecognizer(tap)
        self.image.image = self.images.first
        // Do any additional setup after loading the view, typically from a nib.
    }
    /**
     * 提示:转场的动画的类型(type)和子头型(subtype) 能用字符串常量就用字符常量
     */


     /**
     *******************************************************
     type:动画类型(比如:滴水效果,翻转效果...)
     -------------------------------------------------------
     fade kCATransitionFade 交叉淡化过渡
     moveIn kCATransitionMoveIn 新视图移到旧视图上面
     push kCATransitionPush 新视图把旧视图推出去
     reveal kCATransitionReveal 将旧视图移开,显示下面的新视图
     pageCurl               向上翻一页
     pageUnCurl             向下翻一页
     rippleEffect             滴水效果
     suckEffect 收缩效果,如一块布被抽走
     cube                   立方体效果
     oglFlip              上下左右翻转效果
     rotate     旋转效果
     cameraIrisHollowClose 相机镜头关上效果(不支持过渡方向)
     cameraIrisHollowOpen 相机镜头打开效果(不支持过渡方向)

     *******************************************************
     subtype: 动画方向(比如说是从左边进入,还是从右边进入...)
     ------------------------------------------------------
     kCATransitionFromRight;
     kCATransitionFromLeft;
     kCATransitionFromTop;
     kCATransitionFromBottom;

     当 type 为@"rotate"(旋转)的时候,它也有几个对应的 subtype,分别为:
     90cw 逆时针旋转 90°
     90ccw 顺时针旋转 90°
     180cw 逆时针旋转 180°
     180ccw  顺时针旋转 180°
     **/
    // 改变图片
    func switchImage(tap:UITapGestureRecognizer)
    {
        var imageIndex = 0
        let activeIndex = self.images.indexOf(self.image.image!)
        if tap.locationInView(tap.view).x < (UIScreen.mainScreen().bounds.size.width * 0.5)
        {
            imageIndex = (activeIndex! == 0) ? self.images.count - 1 : activeIndex! - 1
        }
        else
        {
            imageIndex = (activeIndex! == (self.images.count - 1)) ? 0 : activeIndex! + 1
        }
        self.image.image = self.images[imageIndex]
        // 实例化动画对象
        let animation = CATransition()
        // 动画时间
        animation.duration = 2
        // 动画类型
        // `fade', `moveIn', `push' and `reveal'
        animation.type = "moveIn"
        // 动画执行的方向
        //    fromLeft', 动画由左边开始
        //    `fromRight', 动画由右边开始
        //    `fromTop' and
        //    * `fromBottom'
        animation.subtype = "fromBottom"
        // 添加动画到图层
        self.image.layer.addAnimation(animation, forKey: nil)
    }
}

旋转菜单

需要注意的是,设置动画values和fromValue的时候,设置的值代表的是基于最初状态的位置信息,而不是在当前的基础上面增加
自定类方法,这里是定义的xib
//
//  Menu.swift
//  滚动菜单
//
//  Created by admin on 16/1/28.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class Menu: UIView {

    @IBOutlet weak var rootMenu: UIButton!
    private var menus:[UIButton] = []
    private var menusX:[CGFloat] = []
    // 主菜单点击事件
    @IBAction func menuClick(sender: UIButton) {
        // 如果没有子菜单就结束执行
        if self.menus.first == nil
        {
            return
        }
        // 动画执行的时间
        let duration:CFTimeInterval = 3
        // 获得菜单动画信息
        let changeInfo = self.getChangeInfo()
        for var i = 0;i < self.menus.count;i++
        {
            // 初始化当前子菜单的动画组对象
            let animationGroup = CAAnimationGroup()
            // 设置时间
            animationGroup.duration = duration
            // 位移属性变化对象
            let positionX = CAKeyframeAnimation(keyPath: "position.x")
            positionX.values = changeInfo[0][i] as? [AnyObject]
            // 旋转属性赋值
            let rotation = CAKeyframeAnimation(keyPath: "transform.rotation")
            rotation.values = changeInfo[1][i] as? [AnyObject]
            // 把动画添加进组
            animationGroup.animations = [positionX,rotation]
            // 保持动画执行之后的状态
            animationGroup.removedOnCompletion = false
            animationGroup.fillMode = kCAFillModeForwards
            // 设置子菜单属性
            self.menus[i].center.x = changeInfo[0][i].lastObject as! CGFloat
            // 给当前控件添加动画
            self.menus[i].layer.addAnimation(animationGroup, forKey: nil)
        }
        // 主按钮动画效果
        let rootMenuRotation = CABasicAnimation(keyPath: "transform.rotation")
        // 开始位置
        rootMenuRotation.fromValue = (changeInfo[2] as! [CGFloat])[0]
        // 结束位置
        rootMenuRotation.toValue = (changeInfo[2] as! [CGFloat])[1]
        // 保持动画状态
        rootMenuRotation.removedOnCompletion = false
        rootMenuRotation.fillMode = kCAFillModeForwards
        // 时间
        rootMenuRotation.duration = duration
        // 添加动画
        self.rootMenu.layer.addAnimation(rootMenuRotation, forKey: nil)

    }
    // 获得菜单位置改变信息
    func getChangeInfo()->NSMutableArray
    {
        // 平移属性数组
        let transforms:NSMutableArray = []
        // 旋转属性数组
        let rotations:NSMutableArray = []
        // 主菜单按钮旋转属性数组
        var rootMenuRotation:[CGFloat] = []
        // 计算
        for var i = 0;i < self.menus.count;i++
        {
            if self.menus.first?.layer.position.x == self.rootMenu.center.x // 显示
            {
                // 注意这里的参数的含义不是增加这么多,而是在这几个节点的状态
                transforms.addObject([self.rootMenu.center.x,self.menusX[i] * 1.2,self.menusX[i]])
                rotations.addObject([0,M_PI * 4,M_PI * 2])
                rootMenuRotation = [0,CGFloat(M_PI * 0.25)]
            }
            else // 隐藏
            {
                transforms.addObject([self.menus[i].center.x,self.menus[i].center.x * 1.2,self.rootMenu.center.x])
                rotations.addObject([0,M_PI * 2,-M_PI * 2])
                rootMenuRotation = [CGFloat(M_PI * 0.25),0]
            }
        }
        return NSMutableArray(array: [transforms,rotations,rootMenuRotation])
    }
    // 添加子菜单方法,参数为图片名称
    func addMenu(name:String)
    {
        // 获得新添加的图片的名称
        let image = UIImage(imageLiteral: name)
        // 初始化当前子菜单按钮
        let button = UIButton(type: UIButtonType.Custom)
        // 设置图片
        button.setImage(image, forState: UIControlState.Normal)
        // 设置宽高
        button.bounds = CGRectMake(0, 0, 40, 40)
        // 添加进类属性
        self.menus.append(button)
        // 添加到父view
        self.addSubview(button)
        // 需要重新计算各个子菜单的位置,所以需要先置空之前的信息
        self.menusX = []
        // 获得magin
        let margin = ((self.frame.size.width * 0.8 - CGRectGetMaxX(self.rootMenu.frame)) - (CGFloat(self.menus.count) * button.bounds.size.width)) / CGFloat(self.menus.count)
        // 计算各个子控件的位置
        for var i = 0;i < self.menus.count;i++
        {
            // 获得主菜单按钮的中心点x轴坐标
            var preButtonX = self.rootMenu.center.x
            // 如果不是第一个,就获得上个控件的中心点x轴坐标
            if i != 0
            {
                preButtonX = self.menusX[i - 1]
            }
            // 初始化当前位置
            self.menus[i].center = self.rootMenu.center
            // 记录下button位置信息
            self.menusX.append(preButtonX + margin + button.bounds.size.width)
        }
        // 把主按钮设置在最上面显示
        self.bringSubviewToFront(self.rootMenu)
    }
}
控制器中的调用
//
//  ViewController.swift
//  滚动菜单
//
//  Created by admin on 16/1/28.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let menu = NSBundle.mainBundle().loadNibNamed("Menu", owner: nil, options: nil).last as! Menu
        menu.center.y = UIScreen.mainScreen().bounds.size.height * 0.5
        menu.addMenu("menu_btn_call")
        menu.addMenu("menu_btn_cheyou")
        menu.addMenu("menu_btn_tixing")
        self.view.addSubview(menu)
    }
}

核心动画,图标抖动

//
//  ViewController.swift
//  图标抖动
//
//  Created by admin on 16/1/27.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    @IBAction func start(sender: AnyObject) {
        let animation = CAKeyframeAnimation(keyPath: "transform.rotation")
        // 设置path
        animation.values = [-CGFloat(M_PI * 0.1),CGFloat(M_PI * 0.1),-CGFloat(M_PI * 0.1)]
        // 设置重复次数
        animation.repeatCount = Float(CGFloat.max)
        self.imageView.layer.addAnimation(animation, forKey: "shark")
    }
    @IBAction func stop(sender: AnyObject) {
        // 停止动画
        self.imageView.layer.removeAnimationForKey("shark")
    }
}

核心动画CAKeyframeAnimation

//
//  ViewController.swift
//  帧动画
//
//  Created by admin on 16/1/27.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!
    override func viewDidLoad() {
        super.viewDidLoad()
        self.imageView.layer.position = CGPointMake(0, 0)
    }
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let animation = CAKeyframeAnimation(keyPath: "position")
        let imageX = self.imageView.layer.position.x
        let imageY = self.imageView.layer.position.y
        // 第一个位置设置成图层本身的position,不对的话会不好看,会抖一下
        let v1 = NSValue.init(CGPoint: self.imageView.layer.position)
        let v2 = NSValue.init(CGPoint: CGPointMake(imageX + 300,imageY))
        let v3 = NSValue.init(CGPoint: CGPointMake(imageX + 300,imageY + 300))
        let v4 = NSValue.init(CGPoint: CGPointMake(imageX,imageY + 300))
        // 时间
        animation.duration = 10
        // 动画路径
        animation.values = [v1,v2,v3,v4,v1]
        // 节奏
        // kCAMediaTimingFunctionLinear : 匀速
        // kCAMediaTimingFunctionDefault : 慢 -> 快 -> 超级慢
        // kCAMediaTimingFunctionEaseIn : 慢 -> 快 -> 匀速
        // kCAMediaTimingFunctionEaseInEaseOut : 慢 -> 快 -> 慢
        // kCAMediaTimingFunctionEaseOut : 快 -> 慢
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
        // 使用path,因为这里画的是一个圆,所以会沿着这个圆动,
        var path:CGMutablePathRef! = CGPathCreateMutable()
        let screenW = UIScreen.mainScreen().bounds.size.width
        CGPathAddEllipseInRect(path, nil, CGRectMake(0, 0, screenW, screenW))
        // 设置path,path的优先级大于values,所以会执行path
        animation.path = path
        path = nil
        self.imageView.layer.addAnimation(animation, forKey: nil)
    }
}