分类 核心动画 下的文章

模仿网易彩票

注意点:
1.在新建项目时,注意项目的目录结构
2.具有共同操作的类可以新建一个父类来完成公共的操作
3.把实现代码放在控制器类的不同生命周期时调用的方法中,可以避免做重复的操作
4.图片只显示某一部分
5.webView的使用
6.UICollectionViewController的使用
7.模态框的使用
8.自定义TabBarItem

1.目录结构就不说了,mvc
2.共同的父类,子类只要继承自父类,并完成自身的数据赋值即可
//
//  JinBaseTableViewController.swift
//  lottery
//
//  Created by admin on 16/2/4.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit
// 设置界面 UITableViewController 的父类,完成一些公共的操作
class JinBaseTableViewController: UITableViewController {
    // 存放设置选项模型数据
    var settings:[SettingGroup] = []
    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.backgroundColor = UIColor(patternImage: UIImage(imageLiteral: "bg"))
    }

    // 重写构造方法,算是填了下坑吧
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName : nibNameOrNil, bundle : nibBundleOrNil)
    }
    override init(style: UITableViewStyle) {
        super.init(style: style)
        // 在这里设置背景色的话 viewDidload 方法会被调用两次
//        self.tableView.backgroundColor = UIColor(patternImage: UIImage(imageLiteral: "bg"))
    }
    required convenience init?(coder aDecoder: NSCoder) {
        //        fatalError("init(coder:) has not been implemented")
        self.init(style: UITableViewStyle.Grouped)
        //return nil
    }
    convenience init()
    {
        self.init(style: UITableViewStyle.Grouped)
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return self.settings.count
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return self.settings[section].settings.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = JinTableViewCell.instance(tableView, setingData: self.settings[indexPath.section].settings[indexPath.row])
        return cell
    }

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        self.settings[indexPath.section].settings[indexPath.row].block?()
    }
    override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return self.settings[section].title
    }
    override func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? {
        return self.settings[section].footer
    }
}

子类代码

//
//  MyLotteryViewController.swift
//  lottery
//
//  Created by admin on 16/2/3.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class MyLotteryViewController: JinBaseTableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.navigationItem.title = "设置"

        let group1 = SettingGroup()
        group1.settings.append(Setting(title: "推送和提醒", titleImage: UIImage(imageLiteral: "handShake"), accessoryImage: UIImage(imageLiteral: "CellArrow"), block: {
            [unowned self] in
            let controller = PushAndRemindController()
            controller.navigationItem.title = "推送和提醒"
            self.navigationController?.pushViewController(controller, animated: true)
        }))

        group1.settings.append(Setting(title: "摇一摇机选", titleImage: UIImage(imageLiteral: "handShake"), accessory: UISwitch()))
        group1.settings.append(Setting(title: "声音和效果", titleImage: UIImage(imageLiteral: "handShake"), accessory: UISwitch()))
        self.settings.append(group1)
        let group2 = SettingGroup()
        group2.settings.append(Setting(title: "检查版本更新", titleImage: UIImage(imageLiteral: "handShake"), accessoryImage: UIImage(imageLiteral: "CellArrow"), block: {
                [unowned self] in
                let hud = MBProgressHUD.showHUDAddedTo(self.tableView, animated: true)
                hud.label.text = "正在检查更新"
                let time = dispatch_time(DISPATCH_TIME_NOW, Int64(UInt64(2) * NSEC_PER_SEC))
                dispatch_after(time, dispatch_get_main_queue(), {
                    let image = UIImage(imageLiteral: "Checkmark").imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
                    let imageView = UIImageView(image: image)
                    hud.customView = imageView
                    hud.mode = MBProgressHUDMode.CustomView
                    hud.label.text = "已是最新版本"
                    hud.hideAnimated(true, afterDelay: 1)
                })
            }))
        group2.settings.append(Setting(title: "帮助", titleImage: UIImage(imageLiteral: "handShake"), accessoryImage: UIImage(imageLiteral: "CellArrow"), block: {
            [unowned self] in
            let controller = HelpViewController()
            // 因为是自定义的 UITabBarItem 所以这里设置了也无效
//            controller.hidesBottomBarWhenPushed = false
            controller.navigationItem.title = "帮助"

            self.navigationController?.pushViewController(controller, animated: true)
            }))
        group2.settings.append(Setting(title: "分享", titleImage: UIImage(imageLiteral: "handShake"), accessoryImage: UIImage(imageLiteral: "CellArrow")))
        group2.settings.append(Setting(title: "查看消息", titleImage: UIImage(imageLiteral: "handShake"), accessoryImage: UIImage(imageLiteral: "CellArrow")))
        group2.settings.append(Setting(title: "产品推荐", titleImage: UIImage(imageLiteral: "handShake"), accessoryImage: UIImage(imageLiteral: "CellArrow"), block: {
            [unowned self] in
            let controller = ProductViewController(collectionViewLayout : UICollectionViewFlowLayout())
            controller.navigationItem.title = "产品推荐"
            self.navigationController?.pushViewController(controller, animated: true)
            }))
        group2.settings.append(Setting(title: "投信", titleImage: UIImage(imageLiteral: "handShake"), accessoryImage: UIImage(imageLiteral: "CellArrow")))
        self.settings.append(group2)
    }

}
3.在控制器特定的生命周期做操作,可以避免重复的操作
//
//  JinNavigationController.swift
//  lottery
//
//  Created by admin on 16/2/3.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class JinNavigationController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // 修改navgation标题栏的样式,在这里改也行,但是这个方法会执行多次,所以最好使用 initialize
//        self.navigationBar.setBackgroundImage(UIImage(imageLiteral: "NavBar64"), forBarMetrics: UIBarMetrics.Default)
//        self.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor(),NSFontAttributeName:UIFont.systemFontOfSize(20)]
        // Do any additional setup after loading the view.
    }
    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return UIStatusBarStyle.LightContent
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    // 当类第一次创建的时候调用这个方法,避免执行多次
    override class func initialize()
    {
        // 获取UINavigationBar对象
        weak var nav = UINavigationBar.appearance()
        // 设置背景图片
        nav!.setBackgroundImage(UIImage(imageLiteral: "NavBar64"), forBarMetrics: UIBarMetrics.Default)
        // 设置字体属性
        nav!.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor(),NSFontAttributeName:UIFont.systemFontOfSize(20)]
        // 设置返回按钮颜色
        nav!.tintColor = UIColor.whiteColor()
    }
}
4.图片显示某一部分
//
//  SquareViewController.swift
//  lottery
//
//  Created by admin on 16/2/4.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class SquareViewController: UIViewController {
    @IBOutlet weak var wheel: UIImageView!
    var link:CADisplayLink!
    var highlightedButton:UIButton!
    override func viewDidLoad() {
        // 转盘背景图片
        let imageView = UIImageView(image: UIImage(imageLiteral: "LuckyBackground"))
        imageView.frame = self.view.bounds
        self.view.insertSubview(imageView, atIndex: 0)
        // 获得屏幕scale,之后截取图片的时候会用到,不然图片截取之后是不规则的
        let scale = UIScreen.mainScreen().scale
        // 获得选项按钮背景图片
        let strology = UIImage(imageLiteral: "LuckyAstrology")
        let strologyPressed = UIImage(imageLiteral: "LuckyAstrologyPressed")
        // 获得截取图片的宽度
        let buttonW = strology.size.width / 12
        // 获得选项按钮的宽度
        let buttonFrame = CGRectMake(0, 0, buttonW, wheel.bounds.size.width * 0.5)
        // 设置图层的anchorPoint的值,旋转是围绕这个点旋转的
        let buttonLayerAnchorPoint = CGPointMake(0.5, 1)
        // 选项按钮放倒转盘中
        for var i = 0;i < 12;i++
        {
            let button = JinButton(type: UIButtonType.Custom)
            button.tag = i + 1
            button.frame = buttonFrame
            button.layer.anchorPoint = buttonLayerAnchorPoint
            button.center = CGPointMake(self.wheel.bounds.size.width * 0.5, self.wheel.bounds.size.width * 0.5)
            // 从大图片中截取一部分作为当前按钮的背景图片
            var buttonImage = CGImageCreateWithImageInRect(strology.CGImage, CGRectMake(buttonW * CGFloat(i) * scale, 0, buttonW * scale, strology.size.height * scale))
            button.setImage(UIImage(CGImage: buttonImage!), forState: UIControlState.Normal)
            buttonImage = CGImageCreateWithImageInRect(strologyPressed.CGImage, CGRectMake(buttonW * CGFloat(i) * scale, 0, buttonW * scale, strology.size.height * scale))
            // 设置选中状态下的图片
            button.setImage(UIImage(CGImage: buttonImage!), forState: UIControlState.Selected)
            button.setBackgroundImage(UIImage(imageLiteral: "LuckyRototeSelected"), forState: UIControlState.Selected)
            // 设置当前按钮的transform
            button.transform = CGAffineTransformMakeRotation(CGFloat(M_PI) / 6 * CGFloat(i))
            // 禁用高亮
            button.adjustsImageWhenHighlighted = false

            button.addTarget(self, action: "choiceNumber:", forControlEvents: UIControlEvents.TouchDown)
            self.wheel.addSubview(button)
        }
        // 添加开始选号按钮
        let choiceNumberButton = UIButton(type: UIButtonType.Custom)
        let choiceNumberButtonImage = UIImage(imageLiteral: "LuckyCenterButton")
        choiceNumberButton.bounds = CGRectMake(0, 0, choiceNumberButtonImage.size.width, choiceNumberButtonImage.size.height)
        choiceNumberButton.setBackgroundImage(choiceNumberButtonImage, forState: UIControlState.Normal)
        choiceNumberButton.setBackgroundImage(UIImage(imageLiteral: "LuckyCenterButtonPressed"), forState: UIControlState.Highlighted)
        choiceNumberButton.addTarget(self, action: "choiceNumberButtonClicked", forControlEvents: UIControlEvents.TouchDown)
        choiceNumberButton.center = self.wheel.center
        self.view.addSubview(choiceNumberButton)
        self.timer()
    }
    // 开始定时器
    func timer()
    {
        self.link = CADisplayLink(target: self, selector: "startRotation")
        self.link.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
    }
    // 旋转
    func startRotation()
    {
        self.wheel.transform = CGAffineTransformRotate(self.wheel.transform, CGFloat(M_PI) * 0.001)
    }
    // 选项按钮点击事件
    func choiceNumber(button:UIButton)
    {
        self.highlightedButton?.selected = false
        button.selected = true
        self.highlightedButton = button
    }
    func choiceNumberButtonClicked()
    {
        self.link?.invalidate()
        self.link = nil
        self.view.userInteractionEnabled = false
        UIView.transitionWithView(self.wheel, duration: 3, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
                [unowned self] in
                self.wheel.transform = CGAffineTransformRotate(self.wheel.transform, CGFloat(M_PI * 0.9))
            }, completion: {
                [unowned self] bool in
                let tag = Int(arc4random_uniform(12)) + 1
                let button:UIButton = self.wheel.viewWithTag(tag) as! UIButton
                self.choiceNumber(button)
                self.view.userInteractionEnabled = true
                //这里设置下延时执行,之前没用过的一种方式,这个参数有一些特别,而且没有提示。。。。记录下
                let minseconds = 3 * Double(NSEC_PER_SEC)
                let dtime = dispatch_time(DISPATCH_TIME_NOW, Int64(minseconds))
                if self.link == nil
                {
                    dispatch_after(dtime, dispatch_get_main_queue(), { [unowned self] () -> Void in
                        self.timer()
                    })
                }
        })
    }
}
5.webView的使用
//
//  HtmlViewController.swift
//  lottery
//
//  Created by admin on 16/2/4.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class HtmlViewController: UIViewController,UIWebViewDelegate {
    weak var help:Help!
    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = self.help.title
        let webview = UIWebView(frame: UIScreen.mainScreen().bounds)
        webview.delegate = self
        // 获得html文件路径
        let path = NSBundle.mainBundle().pathForResource("help.html", ofType: nil)
        // 获得请求字串
        let request = NSURLRequest(URL: NSURL(fileURLWithPath: path!))
        // 使用webView加载html
        webview.loadRequest(request)
        // 因为是使用模态框加载的这个控制器,所以需要手动设置下返回按钮
        self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "返回", style: UIBarButtonItemStyle.Plain, target: self, action: "back")
        // 把webView添加进视图
        self.view.addSubview(webview)
    }
    // 返回之前的控制器
    func back()
    {
        self.dismissViewControllerAnimated(true, completion: nil)
    }
    // webView代理方法,加载完成时调用
    func webViewDidFinishLoad(webView: UIWebView) {
        // 执行js代码
        let jsCode = "window.location.href='#\(self.help.id)'"
        webView.stringByEvaluatingJavaScriptFromString(jsCode)
    }
}
6.UICollectionViewController的使用
//
//  ProductViewController.swift
//  lottery
//
//  Created by admin on 16/2/4.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit
let collectionIdentifier = "jinCollectionCell"
class ProductViewController: UICollectionViewController {
    // 产品数据模型数组
    lazy var products:[Product] = Product.instanceOfFile()
    // 重写构造方法
    override init(collectionViewLayout layout: UICollectionViewLayout) {
        // cell的大小是通过Layout来控制
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSizeMake(100, 120)
        super.init(collectionViewLayout : layout)
    }
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName : nibNameOrNil, bundle : nibBundleOrNil)
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        self.collectionView?.backgroundColor = UIColor.whiteColor()
        // 和tableView不同的是,需要先注册cell
//        self.collectionView?.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionIdentifier)
        self.collectionView?.registerNib(UINib(nibName: "JinCollectionCell", bundle: NSBundle.mainBundle()), forCellWithReuseIdentifier: collectionIdentifier)
    }
    // 返回分组数
    override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }
    // 返回分组数据条数
    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.products.count
    }
    // 返回cell
    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        // 从缓冲池中获取cell
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(collectionIdentifier, forIndexPath: indexPath) as! JinCollectionCell
        cell.product = self.products[indexPath.row]
        return cell
    }
    override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        let appliction = UIApplication.sharedApplication()
        // 打开url
        appliction.openURL(NSURL(string: self.products[indexPath.row].url)!)
    }
}
7.模态框的使用
//
//  HelpViewController.swift
//  lottery
//
//  Created by admin on 16/2/4.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class HelpViewController: JinBaseTableViewController {
    var helps:[Help] = Help.instanceOfFile()
    override func viewDidLoad() {
        super.viewDidLoad()
        print(helps)
        let group1 = SettingGroup()
        helps.forEach({
            val in
            group1.settings.append(Setting(title: val.title!, accessoryImage: UIImage(imageLiteral: "CellArrow")))
        })

        self.settings.append(group1)
    }
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        // 创建要显示的控制器
        let html = HtmlViewController()
        html.help = self.helps[indexPath.row]
        // 创建导航控制器并把要显示的控制器作为根控制器
        let nav = UINavigationController(rootViewController: html)
        // 显示模态窗口
        self.presentViewController(nav, animated: true, completion: nil)
    }
}
8.自定义TabBarItem
//
//  JinTabBarItem.swift
//  lottery
//
//  Created by admin on 16/2/3.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit
// 自定义协议
@objc protocol JinTabBarItemDelegate
{
    optional func tabBarButtonClicked(index:Int)
}
// 自定义 tabbaritem 类
class JinTabBarItem: UIView {

    // 记录当前选中状态的按钮
    weak var selectedTabBarButton:UIButton!
    // 当前对象代理
    weak var tabBarButtonDelegate:JinTabBarItemDelegate!
    // 添加item按钮
    func addTabBarButton(normalImage:String,selectedImage:String)
    {
        let tabBarButton = UIButton(type: UIButtonType.Custom)
        // 设置图片
        tabBarButton.setBackgroundImage(UIImage(imageLiteral: normalImage), forState: UIControlState.Normal)
        tabBarButton.setBackgroundImage(UIImage(imageLiteral: selectedImage), forState: UIControlState.Selected)
        // 设置图片方法
        tabBarButton.addTarget(self, action: "changeTabBarButtonStatus:", forControlEvents: UIControlEvents.TouchDown)
        // button 没有 setHighlighted 方法啊  我去
        tabBarButton.adjustsImageWhenHighlighted = false
        self.addSubview(tabBarButton)
    }
    // 按钮被点击时的响应事件
    func changeTabBarButtonStatus(button:UIButton)
    {
        // 修改当前选中按钮状态
        self.selectedTabBarButton?.selected = false
        // 修改当前点击按钮状态
        button.selected = true
        // 修改当前被选中的按钮
        self.selectedTabBarButton = button
        // 执行代理方法
        self.tabBarButtonDelegate?.tabBarButtonClicked?(self.subviews.indexOf(button)!)
    }
    // 完成按钮的布局
    override func layoutSubviews() {
        // 获得当前的子按钮数量
        let buttonCount = self.subviews.count
        // 获得当前状态下按钮的宽度
        let buttonWidth = self.frame.size.width / CGFloat(buttonCount)
        for(var i = 0;i < buttonCount;i++)
        {
            let tabBarButton = self.subviews[i] as! UIButton
            // 默认第一个按钮为选中
            if i == 0
            {
                self.changeTabBarButtonStatus(tabBarButton)
            }
            // 设置按钮fram
            tabBarButton.frame = CGRectMake(CGFloat(i) * buttonWidth, 0, buttonWidth, self.frame.size.height)
        }
    }
}

代码网址:https://git.oschina.net/JinDev/lottory.git

动画总结

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

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var image: UIImageView!
    override func viewDidLoad() {
        super.viewDidLoad()
        // 控件的center和控件layer的position是默认相等的
        print(self.image.center)
        // anchorPoint相对于上级layer的坐标,注意anchorPoint和position的互相影响
        print(self.image.layer.position)
        print(self.image.layer.anchorPoint)
    }
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.animationD()
    }
    // 核心动画,需要知道的事,动画改编的position是假象,其实值并没有改变,只是看上去变了
    func animationD()
    {
        let animation = CABasicAnimation(keyPath: "position")
        animation.duration = 3
        animation.delegate = self
        self.image.layer.position = CGPointMake(100, 100)
        print("开始时的position")
        print(self.image.layer.position)
        self.image.layer.addAnimation(animation, forKey: nil)
    }
    override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
        print("结束时的position")
        print(self.image.layer.position)
    }
    // 这个好。。
    func animationC()
    {
        UIView.transitionWithView(self.image, duration: 3, options: UIViewAnimationOptions.TransitionCurlDown, animations: {
                self.image.image = UIImage(imageLiteral: "2")
            }, completion: {
                _ in
            print("动画执行完成")
        })
    }
    //
    func animationB()
    {
        UIView.animateWithDuration(3, animations: {
            // 切换图片没有动态
            self.image.center = CGPointMake(100, 100)
        })
    }
    // UIView动画
    func animationA()
    {
        UIView.beginAnimations(nil, context: nil)
        // 设置事件
        UIView.setAnimationDuration(3)
        // 设置代理
        UIView.setAnimationDelegate(self)
        UIView.setAnimationDidStopSelector("stop")
        // 实现动画代码,切换图片没有效果。。。
        self.image.center = CGPointMake(100, 100)
        UIView.commitAnimations()
    }
    func stop()
    {
        print("动画结束啦")
    }
}

车小弟模仿

需要注意的是几个动画对象的同时使用
//
//  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)
    }
}