Youtube play button animation using POP

NO IMAGE

Youtube play button animation using POP

原文連結

初始專案

第一步呢就是建立一個UIButton的子類叫做PlayButton

正如你所看到的那個樣子這個按鈕呢有兩種狀態一種是播放一種是暫停,這裡呢我們再定義一個列舉

enum PlayButtonState: CGFloat {
    case Paused = 0.0
    case Playing = 1.0
}

在之後會詳細的描述為什麼這裡宣告瞭 var value: CGFloat

這裡講解下實現這兩種狀態的轉換的動畫實現原理

POP允許我們建立動畫的屬性 – 而這正是我們要做的。我們將建立一個名為animationValue一個CGFloat的變數,將1.0動畫播放到0.0時,從暫停的按鈕狀態更改為播放,動畫從0.0到1.0的時候從播放到暫停的按鈕狀態變化。每次值發生了變化,我們會呼叫setNeedsDisplay這將使view重新繪畫

我們將宣告下邊兩個變數:

// MARK: Vars
private(set) var buttonState = PlayButtonState.Playing  
private var animationValue: CGFloat = 1.0 {  
  didSet {
    setNeedsDisplay()
  }
}
  1. buttonState僅僅在這個類中是可寫入的,記錄了按鈕的狀態

  2. animationValue 當它的值發生改變的時候我們呼叫setNeedsDisplay

The next step is to create a method responsible for setting up animation or only updating animationValue when animation is not needed

接下來我們會建立一個方法來負責設定動畫,或者它不需要動畫時僅僅更新animationValue

    // MARK: Methods
    func setButtonState(buttonState: PlayButtonState, animated: Bool) {
        // 1
        if self.buttonState == buttonState {
            return
        }
        self.buttonState = buttonState
        
        // 2
        if pop_animationForKey("animationValue") != nil {
            pop_removeAnimationForKey("animationValue")
        }
        
        // 3
        let toValue: CGFloat = buttonState.rawValue
        
        // 4
        if animated {
            let animation: POPBasicAnimation = POPBasicAnimation()
            if let property = POPAnimatableProperty.propertyWithName("animationValue", initializer: { (prop: POPMutableAnimatableProperty!) -> Void in
                prop.readBlock = { (object: AnyObject!, values: UnsafeMutablePointer<CGFloat>) -> Void in
                    if let button = object as? PlayButton {
                        values[0] = button.animationValue
                    }
                }
                prop.writeBlock = { (object: AnyObject!, values: UnsafePointer<CGFloat>) -> Void in
                    if let button = object as? PlayButton {
                        button.animationValue = values[0]
                    }
                }
                prop.threshold = 0.01
            }) as? POPAnimatableProperty {
                animation.property = property
            }
            
            animation.fromValue = NSNumber(float: Float(self.animationValue))
            animation.toValue = NSNumber(float: Float(toValue))
            animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
            animation.duration = 0.25
            pop_addAnimation(animation, forKey: "percentage")
        } else {
            animationValue = toValue
        }
    }
  1. 只有當我們改變按鈕的狀態的時候我們才去執行動畫

  2. 如果之前的動畫存在的話我們把它移出

  3. 用一個常量來儲存按鈕狀態的原始值

  4. If animation is required, then we initialise POPBasicAnimation with POPAnimatableProperty. Otherwise we only update animation value

接下來我們重寫drawRect方法

    
    // MARK: Draw
    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        
        // 1
        let height = rect.height
        let minWidth = rect.width * 0.32 // 暫停按鈕兩個矩形的寬度
           // aWidth 是由 animationValue 的值來決定的
           //當 animationValue 為 1 時 (要顯示播放按鈕) 所以這個值為 rect.width / 2.0 - minWidth
           //當 animationValue 為 0 時 (要顯示暫停按鈕)所以這個值為 0
        let aWidth = (rect.width / 2.0 - minWidth) * animationValue
        let width = minWidth   aWidth
        //當 animationValue 為 1 時 (要顯示播放按鈕) h1 為 height / 4.0
        //當 animationValue 為 0 時 (要顯示暫停按鈕) h1 為 0
        let h1 = height / 4.0 * animationValue
        
        //當 animationValue 為 1 時 (要顯示播放按鈕) h2 為 height / 2.0
        //當 animationValue 為 0 時 (要顯示暫停按鈕) h2 為 0
        let h2 = height / 2.0 * animationValue
        
        // 2
        let context = UIGraphicsGetCurrentContext()
        
        // 3
        CGContextMoveToPoint(context, 0.0, 0.0)
        CGContextAddLineToPoint(context, width, h1)
        CGContextAddLineToPoint(context, width, height - h1)
        CGContextAddLineToPoint(context, 0.0, height)
        CGContextMoveToPoint(context, rect.width - width, h1)
        CGContextAddLineToPoint(context, rect.width, h2)
        CGContextAddLineToPoint(context, rect.width, height - h2)
        CGContextAddLineToPoint(context, rect.width - width, height - h1)
        
        // 4
        CGContextSetFillColorWithColor(context, tintColor.CGColor)
        CGContextFillPath(context)
    }

相關文章

IOS開發 最新文章