需要注意的是,设置动画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)
}
}