swift - 頭像彈性動畫,類似即刻App的頭像動畫

首先附上 Demo地址

看下我們實現(xiàn)的效果

Untitled1.gif

效果實現(xiàn)應(yīng)該有很多種方法,先講一下涉及到的幾個動畫屬性

1.UIDynamicAnimator 仿真物理屬性,不懂的可以看下邊的網(wǎng)頁鏈接進行學習奧
UIDynamicAnimator - 仿真物理學
2.UISnapBehavior 動力彈性屬性,下邊附帶學習鏈接
UISnapBehavior - 動力學
3.UIAttachmentBehavior,吸附效果屬性,下邊是學習鏈接
UIAttachmentBehavior - 吸附效果
4.最后就是我們的UIPanGestureRecognizer這個我們都熟悉的手勢了,

大家如果對這幾個物理仿真屬性不是太了解的也可以自行百度查找學習一下

為了方便外部使用,這里通過UIView的擴展(extension)實現(xiàn)上述效果,調(diào)用比較方便,
//object代表UIView的子類,直接調(diào)用這句話即可
object.signleDragable()

我們來看下代碼實現(xiàn)這塊,因為考慮到在擴展里邊沒辦法直接添加屬性,因此。我們用到了OC里的那一套,用runtime來添加

上圖
image.png
上代碼

    private var zm_playground: UIView? {
        set{
            objc_setAssociatedObject(self, RuntimeKey.zm_playgroundKey!, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get{
            return objc_getAssociatedObject(self, RuntimeKey.zm_playgroundKey!) as? UIView
        }
    }
    
    private var zm_animator: UIDynamicAnimator? {
        set{
            objc_setAssociatedObject(self, RuntimeKey.zm_animatorKey!, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get{
            return objc_getAssociatedObject(self, RuntimeKey.zm_animatorKey!) as? UIDynamicAnimator
        }
    }
    
    private var zm_snapBehavior: UISnapBehavior? {
        set{
            objc_setAssociatedObject(self, RuntimeKey.zm_snapBehavior!, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get{
            return objc_getAssociatedObject(self, RuntimeKey.zm_snapBehavior!) as? UISnapBehavior
        }
    }
    
    private var zm_attachmentBehavior: UIAttachmentBehavior? {
        set{
            objc_setAssociatedObject(self, RuntimeKey.zm_attachmentBehavior!, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get{
            return objc_getAssociatedObject(self, RuntimeKey.zm_attachmentBehavior!) as? UIAttachmentBehavior
        }
    }
    
    private var zm_panGesture: UIPanGestureRecognizer? {
        set{
            objc_setAssociatedObject(self, RuntimeKey.zm_panGesture!, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get{
            return objc_getAssociatedObject(self, RuntimeKey.zm_panGesture!) as? UIPanGestureRecognizer
        }
    }
    
    private var zm_centerPoint: CGPoint? {
        set{
            objc_setAssociatedObject(self, RuntimeKey.zm_centerPoint!, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get{
            return objc_getAssociatedObject(self, RuntimeKey.zm_centerPoint!) as? CGPoint
        }
    }
    
    private var zm_damping: CGFloat? {
        set{
            objc_setAssociatedObject(self, RuntimeKey.zm_damping!, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get{
            return objc_getAssociatedObject(self, RuntimeKey.zm_damping!) as? CGFloat
        }
    }

這里用這個runtime之前我還專門百度一下和OC的用法區(qū)別,果不其然。有人說key這個玩意不定義好容易為空,具體我也沒細看原因。

因此,一方面為了方便,另一方面為了后期擴展,自己定義了一個結(jié)構(gòu)體來承載這些key
image.png
    static let zm_playgroundKey = UnsafeRawPointer.init(bitPattern: "zm_playgroundKey".hashValue)
    static let zm_animatorKey = UnsafeRawPointer.init(bitPattern: "zm_animatorKey".hashValue)
    static let zm_snapBehavior = UnsafeRawPointer.init(bitPattern: "zm_snapBehaviorKey".hashValue)
    static let zm_attachmentBehavior = UnsafeRawPointer.init(bitPattern: "zm_attachmentBehaviorKey".hashValue)
    static let zm_panGesture = UnsafeRawPointer.init(bitPattern: "zm_panGestureKey".hashValue)
    static let zm_centerPoint = UnsafeRawPointer.init(bitPattern: "zm_centerPointKey".hashValue)
    static let zm_damping = UnsafeRawPointer.init(bitPattern: "zm_dampingKey".hashValue)
我們來看下核心功能區(qū),pan手勢那里都進行了什么操作
image.png
//swift 4.0語法,記得方法帶上@objc
    @objc func signlePanGesture(pan: UIPanGestureRecognizer) -> Void {
        let panLocation = pan.location(in: zm_playground)
        if pan.state == .began {
            signleUpdateSnapPoint()
            let offSet = UIOffsetMake(panLocation.x - (zm_centerPoint?.x)!, panLocation.y - (zm_centerPoint?.y)!)
            zm_animator?.removeAllBehaviors()
            zm_attachmentBehavior = UIAttachmentBehavior.init(item: self, offsetFromCenter: offSet, attachedToAnchor: panLocation)
            zm_animator?.addBehavior(zm_attachmentBehavior!)
        } else if pan.state == .changed {
            zm_attachmentBehavior?.anchorPoint = panLocation
        } else if (pan.state == .ended) || (pan.state == .cancelled) || (pan.state == .failed) {
            zm_animator?.addBehavior(zm_snapBehavior!)
            zm_animator?.removeBehavior(zm_attachmentBehavior!)
        }
    }

這里分了幾個步驟實現(xiàn)

1.當手勢觸發(fā)時,添加UISnapBehavior 動力彈性屬性,UIAttachmentBehavior - 吸附效果,并且放到我們的UIDynamicAnimator 仿真物理屬性這個里邊
2.當手勢開始發(fā)生改變的時候,我們看動畫可以看出,是一直跟著手勢滑動的,因此這里把中心點坐標拿了出來
3.當我們手勢結(jié)束,取消,或者出現(xiàn)了不可控的情況導致手勢結(jié)束的情況下,移除當前動畫效果就可以了

以上就是關(guān)于swift版,頭像仿物理引擎動畫。 Demo地址

有疑問的同學,可以下方評論區(qū)探討奧
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容