Skip to content

Instantly share code, notes, and snippets.

@cennydavidsson
Created October 27, 2014 10:31
Show Gist options
  • Select an option

  • Save cennydavidsson/d30dc422255fe63fdb2b to your computer and use it in GitHub Desktop.

Select an option

Save cennydavidsson/d30dc422255fe63fdb2b to your computer and use it in GitHub Desktop.
//
// AttatchButton.swift
// Solution
//
// Created by Cenny Davidsson on 2014-10-26.
// Copyright (c) 2014 Cenny. All rights reserved.
//
import UIKit
class AttatchButton: UIButton {
// MARK: Properties
private var snapshootView: UIView!
private var attatchmentBehavior: UIAttachmentBehavior!
private var currentEvent: UIEvent!
private var touchIsOutSide = false
private lazy var animator: UIDynamicAnimator = { [unowned self] in
return UIDynamicAnimator(referenceView: self.superview!)
}()
private lazy var gravity: UIGravityBehavior = { [unowned self] in
var gravity = UIGravityBehavior()
gravity.magnitude = 3
gravity.action = { [unowned self] in
if !self.snapshootView.frame.intersects(self.superview!.frame) {
gravity.removeItem(self.snapshootView)
}
}
self.animator.addBehavior(gravity)
return gravity
}()
// MARK: Init
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
addTargets()
}
override init(frame: CGRect) {
super.init(frame: frame)
addTargets()
}
private func addTargets() {
[("touchDown", UIControlEvents.TouchDown),
("touchUpInside", UIControlEvents.TouchUpInside),
("touchDragOutside", UIControlEvents.TouchDragOutside),
("touchDragInside", UIControlEvents.TouchDragInside),
("touchUpOutside", UIControlEvents.TouchUpOutside)]
.map {
self.addTarget(self, action: $0.0, forControlEvents: $0.1)
}
}
// MARK: UIControll
override func sendAction(action: Selector, to target: AnyObject?,forEvent event: UIEvent?) {
currentEvent = event
super.sendAction(action, to: target, forEvent: event)
}
// MARK: Handle touch actions
func touchDown() {
// Create a copy view from orginal and hide orginial
snapshootView = snapshotViewAfterScreenUpdates(true)
snapshootView.frame = frame
snapshootView.setShadowWithOffset(CGSize(), radius: 2, opacity: 0.5)
superview!.addSubview(snapshootView)
hidden = true
// Apply dynamics
let touch = currentEvent.touchesForView(self)!.anyObject()! as UITouch
let touchInButton = touch.locationInView(self)
let offset = UIOffset(horizontal: touchInButton.x - snapshootView.bounds.width/2, vertical: touchInButton.y - snapshootView.bounds.height/2)
attatchmentBehavior = UIAttachmentBehavior(item: snapshootView, offsetFromCenter: offset, attachedToAnchor: touch.locationInView(superview!))
animator.addBehavior(attatchmentBehavior)
gravity.addItem(snapshootView)
}
func touchUpInside() {
animator.removeBehavior(attatchmentBehavior)
}
func touchUpOutside() {
snapshootView.removeFromSuperview()
}
func touchDragOutside() {
if !touchIsOutSide {
touchIsOutSide = true
// Remove dangling state
animator.removeBehavior(attatchmentBehavior)
gravity.removeItem(snapshootView)
// Return to orginial state
UIView.animateWithDuration(0.3, animations: {
self.snapshootView.transform = CGAffineTransformIdentity
self.snapshootView.frame = self.frame
}) { [unowned self] (_) in
self.snapshootView.hidden = true
self.hidden = false
}
}
}
func touchDragInside() {
if touchIsOutSide {
touchIsOutSide = false
hidden = true
snapshootView.hidden = false
// Resume dangling state
animator.addBehavior(attatchmentBehavior)
gravity.addItem(snapshootView)
}
}
// Animation
func animateButtonBack() {
gravity.removeItem(snapshootView)
UIView.animateWithDuration(0.7, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.6,
options: .AllowUserInteraction | .AllowAnimatedContent | .BeginFromCurrentState,
animations: { [unowned self] in
self.snapshootView.transform = CGAffineTransformIdentity
self.snapshootView.frame = self.frame
}) { [unowned self] (_) in
// Return to orginial state
self.snapshootView.removeFromSuperview()
self.hidden = false
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment