Skip to content
This repository has been archived by the owner on May 23, 2022. It is now read-only.

Commit

Permalink
Merge pull request #6 from morizotter/morizotter/improve-animation
Browse files Browse the repository at this point in the history
Improve animation
  • Loading branch information
morizotter committed Jun 24, 2015
2 parents edd3f61 + a557531 commit 1dffc35
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 74 deletions.
2 changes: 1 addition & 1 deletion SwiftyDrop.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SwiftyDrop"
s.version = "1.0.1"
s.version = "1.0.2"
s.summary = "SwiftyDrop is a lightweight pure Swift simple and beautiful dropdown message."

s.description = <<-DESC
Expand Down
166 changes: 93 additions & 73 deletions SwiftyDrop/Drop.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public final class Drop: UIView {
private let statusTopMargin: CGFloat = 8.0
private let statusBottomMargin: CGFloat = 8.0
private var upTimer: NSTimer?
private var startTop: CGFloat?

override init(frame: CGRect) {
super.init(frame: frame)
Expand All @@ -54,20 +55,19 @@ public final class Drop: UIView {
constant: 100.0
)
self.addConstraint(heightConstraint)
restartUpTimer(4.0)
scheduleUpTimer(4.0)
}

required public init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

deinit {
upTimer?.invalidate()
upTimer = nil
stopUpTimer()
}

func up() {
restartUpTimer(0.0)
scheduleUpTimer(0.0)
}

func upFromTimer(timer: NSTimer) {
Expand All @@ -76,14 +76,18 @@ public final class Drop: UIView {
}
}

private func restartUpTimer(after: Double) {
restartUpTimer(after, interval: 0.25)
private func scheduleUpTimer(after: Double) {
scheduleUpTimer(after, interval: 0.25)
}

private func restartUpTimer(after: Double, interval: Double) {
private func scheduleUpTimer(after: Double, interval: Double) {
stopUpTimer()
upTimer = NSTimer.scheduledTimerWithTimeInterval(after, target: self, selector: "upFromTimer:", userInfo: interval, repeats: false)
}

private func stopUpTimer() {
upTimer?.invalidate()
upTimer = nil
upTimer = NSTimer.scheduledTimerWithTimeInterval(after, target: self, selector: "upFromTimer:", userInfo: interval, repeats: false)
}

private func updateHeight() {
Expand All @@ -107,51 +111,49 @@ extension Drop {

private class func down(status: String, state: DropState?, blur: DropBlur?) {
self.upAll()
if let window = window() {
let drop = Drop(frame: CGRectZero)
window.addSubview(drop)

let sideConstraints = ([.Left, .Right] as [NSLayoutAttribute]).map {
return NSLayoutConstraint(
item: window,
attribute: $0,
relatedBy: .Equal,
toItem: drop,
attribute: $0,
multiplier: 1.0,
constant: 0.0
)
}

drop.topConstraint = NSLayoutConstraint(
item: window,
attribute: .Top,
let drop = Drop(frame: CGRectZero)
Drop.window().addSubview(drop)

let sideConstraints = ([.Left, .Right] as [NSLayoutAttribute]).map {
return NSLayoutConstraint(
item: drop,
attribute: $0,
relatedBy: .Equal,
toItem: drop,
attribute: .Top,
toItem: Drop.window(),
attribute: $0,
multiplier: 1.0,
constant: drop.heightConstraint.constant
)

window.addConstraints(sideConstraints)
window.addConstraint(drop.topConstraint)
drop.setup(status, state: state, blur: blur)
drop.updateHeight()

drop.topConstraint.constant = 0.0
UIView.animateWithDuration(
NSTimeInterval(0.25),
delay: NSTimeInterval(0.0),
options: .AllowUserInteraction | .CurveEaseOut,
animations: { [weak drop] () -> Void in
if let drop = drop { drop.layoutIfNeeded() }
}, completion: nil
constant: 0.0
)
}

drop.topConstraint = NSLayoutConstraint(
item: drop,
attribute: .Top,
relatedBy: .Equal,
toItem: Drop.window(),
attribute: .Top,
multiplier: 1.0,
constant: -drop.heightConstraint.constant
)

Drop.window().addConstraints(sideConstraints)
Drop.window().addConstraint(drop.topConstraint)
drop.setup(status, state: state, blur: blur)
drop.updateHeight()

drop.topConstraint.constant = 0.0
UIView.animateWithDuration(
NSTimeInterval(0.25),
delay: NSTimeInterval(0.0),
options: .AllowUserInteraction | .CurveEaseOut,
animations: { [weak drop] () -> Void in
if let drop = drop { drop.layoutIfNeeded() }
}, completion: nil
)
}

private class func up(drop: Drop, interval: NSTimeInterval) {
drop.topConstraint.constant = drop.heightConstraint.constant
drop.topConstraint.constant = -drop.heightConstraint.constant
UIView.animateWithDuration(
interval,
delay: NSTimeInterval(0.0),
Expand All @@ -166,11 +168,9 @@ extension Drop {
}

public class func upAll() {
if let window = Drop.window() {
for view in window.subviews {
if let drop = view as? Drop {
drop.up()
}
for view in Drop.window().subviews {
if let drop = view as? Drop {
drop.up()
}
}
}
Expand Down Expand Up @@ -198,7 +198,18 @@ extension Drop {
constant: 0.0
)
}
let topConstraint = NSLayoutConstraint(
item: visualEffectView,
attribute: .Top,
relatedBy: .Equal,
toItem: self,
attribute: .Top,
multiplier: 1.0,
constant: -UIScreen.mainScreen().bounds.height
)

self.addConstraints(visualEffectViewConstraints)
self.addConstraint(topConstraint)
self.backgroundView = visualEffectView

// Vibrancy Effect View
Expand Down Expand Up @@ -230,7 +241,7 @@ extension Drop {
toItem: visualEffectView.contentView,
attribute: .Top,
multiplier: 1.0,
constant: Drop.statusBarHeight() + statusTopMargin
constant: UIScreen.mainScreen().bounds.height + Drop.statusBarHeight() + statusTopMargin
)
let vibrancyBottom = NSLayoutConstraint(
item: vibrancyEffectView,
Expand Down Expand Up @@ -284,7 +295,7 @@ extension Drop {
backgroundView.alpha = 0.9
backgroundView.backgroundColor = state.backgroundColor()
self.addSubview(backgroundView)
let backgroundConstraints = ([.Top, .Right, .Bottom, .Left] as [NSLayoutAttribute]).map {
let backgroundConstraints = ([.Right, .Bottom, .Left] as [NSLayoutAttribute]).map {
return NSLayoutConstraint(
item: backgroundView,
attribute: $0,
Expand All @@ -295,7 +306,19 @@ extension Drop {
constant: 0.0
)
}

let topConstraint = NSLayoutConstraint(
item: backgroundView,
attribute: .Top,
relatedBy: .Equal,
toItem: self,
attribute: .Top,
multiplier: 1.0,
constant: -UIScreen.mainScreen().bounds.height
)

self.addConstraints(backgroundConstraints)
self.addConstraint(topConstraint)
self.backgroundView = backgroundView

// Status Label
Expand Down Expand Up @@ -362,27 +385,23 @@ extension Drop {
let pan = sender as! UIPanGestureRecognizer
switch pan.state {
case .Began:
upTimer?.invalidate()
upTimer = nil
stopUpTimer()
startTop = topConstraint.constant
case .Changed:
if let window = Drop.window() {
let point = pan.translationInView(window)
let location = pan.locationInView(window)

let y = topConstraint.constant - point.y
if y < 0 {
topConstraint.constant = 0.0; break
}
if location.y > self.frame.size.height { break }
topConstraint.constant = y
self.layoutIfNeeded()
pan.setTranslation(CGPointZero, inView: window)
let location = pan.locationInView(Drop.window())
let translation = pan.translationInView(Drop.window())
let top = startTop! + translation.y
if top > 0.0 {
topConstraint.constant = top * 0.2
} else {
topConstraint.constant = top
}
case .Ended:
if topConstraint.constant > 0.0 {
restartUpTimer(0.0, interval: 0.1)
startTop = nil
if topConstraint.constant < 0.0 {
scheduleUpTimer(0.0, interval: 0.1)
} else {
restartUpTimer(2.0)
scheduleUpTimer(4.0)
topConstraint.constant = 0.0
UIView.animateWithDuration(
NSTimeInterval(0.1),
Expand All @@ -394,15 +413,16 @@ extension Drop {
)
}
case .Failed, .Cancelled:
restartUpTimer(2.0)
startTop = nil
scheduleUpTimer(2.0)
case .Possible: break
}
}
}

extension Drop {
private class func window() -> UIWindow? {
return UIApplication.sharedApplication().keyWindow
private class func window() -> UIWindow {
return UIApplication.sharedApplication().keyWindow!
}

private class func statusBarHeight() -> CGFloat {
Expand Down

0 comments on commit 1dffc35

Please sign in to comment.