扩大动画效果,希望你喜欢

1. view 分类: 动画类抽取

  • 效果图
效果图.gif
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)
         }
         
        */
    }
}
  • Nav3ViewController 部分代码
// 返回按钮
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,就动态设定 属于你的 扩大缩小动画
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,392评论 25 707
  • 一起玩! 一起寻宝! 一起大快朵颐!呵呵! 根本停不下来哦! 期待2017年再见面!相信青青幼儿世界紫荆园明年会更精彩!
    黎丹阅读 178评论 0 0
  • 古典老师为了让书的内容看起来更有科技感,借鉴了国外畅销书的风格,跨界引入了例如“跃迁”、“联机学习”、“暗箱”等生...
    薏米饼干阅读 296评论 0 0
  • 我时常倚着五楼的窗户,看,夜色里的整个城市。任风,将心事吹成一张抖动的纸。 我是个江南女子。带着南方的婉约,住进北...
    言禾雨阅读 495评论 9 16