1. view 分类: 动画类抽取
import UIKit
var kDefaultLayerBgColor = UIColor.cyanColor().CGColor
// 扩大方法 CGRectInset(rect, dx, dy) -> 以原rect为中心,再参考dx,dy,进行缩放或者放大, -radius 放大
func expend(center: CGPoint, radius: CGFloat) -> CGRect{
return CGRectInset(CGRect(origin: center, size: CGSizeZero), -radius, -radius)
}
extension UIView{
/**
view 执行圆形动画效果
- parameter durantion: 动画时长
- parameter blewLayer: 扩大的 layer,在 哪个 layer下面:如果 传nil ,就添加到当前视图 的最前面(遮挡下面的layer)
- parameter circleCenter: 圆心
- parameter isOpen: 是打开,还是关闭效果
- parameter animationHandle: 进行动画事的处理事件 : layer -》 扩大 遮盖层layer,我们可以对其进行 处理,如:进行透明度 等动画效果,等等
- parameter completionHandle: 整个动画完成处理事件
*/
func animateCircleAnimation(duration durantion: NSTimeInterval, blewLayer: CALayer? = nil, circleCenter: CGPoint, isOpen: Bool, @noescape animationHandle: (layer: CALayer)-> Void, completionHandle: ((Bool) -> Void)? = nil){
let fillLayer = CALayer()
fillLayer.frame = self.bounds
if let _ = blewLayer{
layer.insertSublayer(fillLayer, below: blewLayer)
}else{
layer.addSublayer(fillLayer)
}
// 获取在 holdView 的中心点
let center = circleCenter
// 利用勾股定理,求出 圆半径
let x = max(center.x, frame.width - center.x)
let y = max(center.y, frame.height - center.y)
let circleRadius = sqrt(x*x + y*y)
// 创建动画对象
var animation: CircleShowAnimator
if isOpen{
fillLayer.opacity = 0.99
animation = CircleShowAnimator(layer: fillLayer, center: center, startRadius: 0, endRadius: circleRadius)
}else{
fillLayer.opacity = 0.99
animation = CircleShowAnimator(layer: fillLayer, center: center, startRadius: circleRadius, endRadius: 0)
}
animation.duration = durantion
animation.completion = { layer in
fillLayer.removeFromSuperlayer()
if let _ = completionHandle{
completionHandle!(true)
}
}
animation.show()
animationHandle(layer: animation.layer)
}
}
class CircleShowAnimator {
var completion: () -> Void = {}
var layer: CALayer
private let mask: CAShapeLayer
private let animation: CABasicAnimation
var duration: CFTimeInterval {
get { return animation.duration }
set(value) { animation.duration = value }
}
var timingFunction: CAMediaTimingFunction! {
get { return animation.timingFunction }
set(value) { animation.timingFunction = value }
}
init(layer: CALayer, center: CGPoint, startRadius: CGFloat, endRadius: CGFloat, isOpen: Bool = false){
// 大小圆路径
let startCirclePath = CGPathCreateWithEllipseInRect(expend(center, radius: startRadius), nil)
let endCirclePath = CGPathCreateWithEllipseInRect(expend(center, radius: endRadius), nil)
var startPath = startCirclePath, endPath = endCirclePath
if isOpen{
var path = CGPathCreateMutable()
CGPathAddRect(path, nil, layer.bounds)
CGPathAddPath(path, nil, startCirclePath)
startPath = path
path = CGPathCreateMutable()
CGPathAddRect(path, nil, layer.bounds)
CGPathAddPath(path, nil, endCirclePath)
endPath = path
}
self.layer = layer
self.layer.backgroundColor = kDefaultLayerBgColor
// CAShapeLayer
mask = CAShapeLayer()
mask.path = endPath
mask.fillRule = kCAFillRuleEvenOdd
animation = CABasicAnimation(keyPath: "path")
animation.fromValue = startPath
animation.toValue = endPath
animation.duration = duration
animation.delegate = AnimationDelegate(completion: { () -> Void in
layer.mask = nil
self.completion()
self.animation.delegate = nil
})
}
func show(){
layer.mask = mask
mask.frame = layer.bounds
mask.addAnimation(animation, forKey: "circleAnima")
}
}
class AnimationDelegate{
private let completion: () -> Void
init(completion: () -> Void) {
self.completion = completion
}
dynamic func animationDidStop(_: CAAnimation, finished: Bool) {
completion()
}
}
2. 使用
import UIKit
class CircleAnimationViewController: UIViewController {
lazy var startBtn: UIButton = {
let btn = UIButton()
btn.size = CGSizeMake(200, 54)
btn.alpha = 0.8
btn.layer.borderColor = UIColor.orangeColor().CGColor
btn.layer.borderWidth = 1
btn.layer.cornerRadius = 27
btn.layer.masksToBounds = true
btn.setTitle("点击", forState: .Normal)
btn.setTitle("跳转", forState: UIControlState.Highlighted)
btn.backgroundColor = UIColor.blackColor()
btn.addTarget(self, action: "startBtnClick", forControlEvents: UIControlEvents.TouchDown)
btn.center = self.view.center
return btn
}()
lazy var LoadBtn: UIButton = {
let btn = UIButton()
btn.frame = CGRectMake(20, 80, 60, 60)
btn.alpha = 0.8
btn.layer.borderColor = UIColor.orangeColor().CGColor
btn.layer.borderWidth = 1
btn.layer.cornerRadius = btn.frame.size.width / 2
btn.layer.masksToBounds = true
btn.setTitle("点击", forState: .Normal)
btn.backgroundColor = UIColor.blueColor()
btn.addTarget(self, action: "enterBtnClick:", forControlEvents: UIControlEvents.TouchUpInside)
return btn
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.whiteColor()
self.view.addSubview(self.startBtn)
self.view.addSubview(LoadBtn)
}
func startBtnClick(){
let center = CGPoint(x: self.startBtn.bounds.midX, y: self.startBtn.bounds.midY)
// 点击按钮进行 扩大动画,动画结束 切换 视图
self.startBtn.animateCircleAnimation(duration: 0.5, blewLayer: self.startBtn.imageView?.layer, circleCenter: center, isOpen: true, animationHandle: { (layer) -> Void in
// 修改 layer 的背景颜色
layer.backgroundColor = UIColor.greenColor().CGColor
layer.opacity = 0
let opacityAnim = CABasicAnimation(keyPath: "opacity")
opacityAnim.fromValue = 0.9
opacityAnim.toValue = 0.6
opacityAnim.duration = 0.5
layer.addAnimation(opacityAnim, forKey: "opacity")
}) { (_) -> Void in
self.navigationController?.pushViewController(Nav3ViewController(), animated: true)
}
}
func enterBtnClick(sender: UIButton){
// 效果一: 扩大动画 在 按钮 下面 blewLayer: sender.layer, 按钮 未被遮盖效果
self.view.animateCircleAnimation(duration: 0.5, blewLayer: sender.layer, circleCenter: sender.center, isOpen: true, animationHandle: { (layer) -> Void in
}) { (_) -> Void in
self.navigationController?.pushViewController(Nav3ViewController(), animated: false)
}
// 效果而: 扩大 动画在按钮上面 , blewLayer 参数未传值, 按钮被遮盖 的效果
/*
self.view.animateCircleAnimation(duration: 0.5, circleCenter: sender.center, isOpen: true, animationHandle: { (layer) -> Void in
}) { (_) -> Void in
self.navigationController?.pushViewController(Nav3ViewController(), animated: false)
}
*/
}
}
// 返回按钮
lazy var backBtn: UIButton = {
let btn = UIButton(frame: CGRectMake(15, 24, 27, 27))
btn.addTarget(self, action: "backBtnClick:", forControlEvents: UIControlEvents.TouchUpInside)
btn.setImage(UIImage(named: "back_normal"), forState: UIControlState.Normal)
return btn
}()
// 2. 返回按钮事件:处理, 退出当前控制器,缩小动画
func backBtnClick(sender: UIButton){
self.view.animateCircleAnimation(duration: 0.5, blewLayer: sender.layer, circleCenter: sender.center, isOpen: false, animationHandle: { (layer) -> Void in
// self.tableView.hidden = true
// self.topScaleImageView.hidden = true
}) { (_) -> Void in
self.navigationController?.popViewControllerAnimated(false)
}
- 当然 如果你觉得 圆形扩大路径不是你想要的效果,你可以 尝试 改变 CGPath,就动态设定 属于你的 扩大缩小动画