首先附上 Demo地址
看下我們實現(xiàn)的效果
效果實現(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來添加
上圖
上代碼
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
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手勢那里都進行了什么操作
//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é)束的情況下是己,移除當前動畫效果就可以了