Skip to content

Commit 71bc982

Browse files
committed
seperate internal classes into their own files too
1 parent 27d890a commit 71bc982

File tree

4 files changed

+262
-237
lines changed

4 files changed

+262
-237
lines changed

ZLSwipeableViewSwift/Scheduler.swift

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// Scheduler.swift
3+
// ZLSwipeableViewSwift
4+
//
5+
// Created by Andrew Breckenridge on 5/17/16.
6+
// Copyright © 2016 Andrew Breckenridge. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
class Scheduler : NSObject {
12+
13+
typealias Action = () -> Void
14+
typealias EndCondition = () -> Bool
15+
16+
var timer: NSTimer?
17+
var action: Action?
18+
var endCondition: EndCondition?
19+
20+
func scheduleRepeatedly(action: Action, interval: NSTimeInterval, endCondition: EndCondition) {
21+
guard timer == nil && interval > 0 else { return }
22+
self.action = action
23+
self.endCondition = endCondition
24+
timer = NSTimer.scheduledTimerWithTimeInterval(interval, target: self, selector: #selector(Scheduler.doAction(_:)), userInfo: nil, repeats: true)
25+
}
26+
27+
func doAction(timer: NSTimer) {
28+
guard let action = action, let endCondition = endCondition where !endCondition() else {
29+
timer.invalidate()
30+
self.timer = nil
31+
self.action = nil
32+
self.endCondition = nil
33+
return
34+
}
35+
action()
36+
}
37+
38+
}
+214
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
//
2+
// ViewManager.swift
3+
// ZLSwipeableViewSwift
4+
//
5+
// Created by Andrew Breckenridge on 5/17/16.
6+
// Copyright © 2016 Andrew Breckenridge. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
class ViewManager : NSObject {
12+
13+
// Snapping -> [Moving]+ -> Snapping
14+
// Snapping -> [Moving]+ -> Swiping -> Snapping
15+
enum State {
16+
case Snapping(CGPoint), Moving(CGPoint), Swiping(CGPoint, CGVector)
17+
}
18+
19+
var state: State {
20+
didSet {
21+
if case .Snapping(_) = oldValue, case let .Moving(point) = state {
22+
unsnapView()
23+
attachView(toPoint: point)
24+
} else if case .Snapping(_) = oldValue, case let .Swiping(origin, direction) = state {
25+
unsnapView()
26+
attachView(toPoint: origin)
27+
pushView(fromPoint: origin, inDirection: direction)
28+
} else if case .Moving(_) = oldValue, case let .Moving(point) = state {
29+
moveView(toPoint: point)
30+
} else if case .Moving(_) = oldValue, case let .Snapping(point) = state {
31+
detachView()
32+
snapView(point)
33+
} else if case .Moving(_) = oldValue, case let .Swiping(origin, direction) = state {
34+
pushView(fromPoint: origin, inDirection: direction)
35+
} else if case .Swiping(_, _) = oldValue, case let .Snapping(point) = state {
36+
unpushView()
37+
detachView()
38+
snapView(point)
39+
}
40+
}
41+
}
42+
43+
/// To be added to view and removed
44+
private class ZLPanGestureRecognizer: UIPanGestureRecognizer { }
45+
private class ZLTapGestureRecognizer: UITapGestureRecognizer { }
46+
47+
static private let anchorViewWidth = CGFloat(1000)
48+
private var anchorView = UIView(frame: CGRect(x: 0, y: 0, width: anchorViewWidth, height: anchorViewWidth))
49+
50+
private var snapBehavior: UISnapBehavior!
51+
private var viewToAnchorViewAttachmentBehavior: UIAttachmentBehavior!
52+
private var anchorViewToPointAttachmentBehavior: UIAttachmentBehavior!
53+
private var pushBehavior: UIPushBehavior!
54+
55+
private let view: UIView
56+
private let containerView: UIView
57+
private let miscContainerView: UIView
58+
private let animator: UIDynamicAnimator
59+
private weak var swipeableView: ZLSwipeableView?
60+
61+
init(view: UIView, containerView: UIView, index: Int, miscContainerView: UIView, animator: UIDynamicAnimator, swipeableView: ZLSwipeableView) {
62+
self.view = view
63+
self.containerView = containerView
64+
self.miscContainerView = miscContainerView
65+
self.animator = animator
66+
self.swipeableView = swipeableView
67+
self.state = ViewManager.defaultSnappingState(view)
68+
69+
super.init()
70+
71+
view.addGestureRecognizer(ZLPanGestureRecognizer(target: self, action: #selector(ViewManager.handlePan(_:))))
72+
view.addGestureRecognizer(ZLTapGestureRecognizer(target: self, action: #selector(ViewManager.handleTap(_:))))
73+
miscContainerView.addSubview(anchorView)
74+
containerView.insertSubview(view, atIndex: index)
75+
}
76+
77+
static func defaultSnappingState(view: UIView) -> State {
78+
return .Snapping(view.convertPoint(view.center, fromView: view.superview))
79+
}
80+
81+
func snappingStateAtContainerCenter() -> State {
82+
guard let swipeableView = swipeableView else { return ViewManager.defaultSnappingState(view) }
83+
return .Snapping(containerView.convertPoint(swipeableView.center, fromView: swipeableView.superview))
84+
}
85+
86+
deinit {
87+
if let snapBehavior = snapBehavior {
88+
removeBehavior(snapBehavior)
89+
}
90+
if let viewToAnchorViewAttachmentBehavior = viewToAnchorViewAttachmentBehavior {
91+
removeBehavior(viewToAnchorViewAttachmentBehavior)
92+
}
93+
if let anchorViewToPointAttachmentBehavior = anchorViewToPointAttachmentBehavior {
94+
removeBehavior(anchorViewToPointAttachmentBehavior)
95+
}
96+
if let pushBehavior = pushBehavior {
97+
removeBehavior(pushBehavior)
98+
}
99+
100+
for gestureRecognizer in view.gestureRecognizers! {
101+
if gestureRecognizer.isKindOfClass(ZLPanGestureRecognizer.classForCoder()) {
102+
view.removeGestureRecognizer(gestureRecognizer)
103+
}
104+
}
105+
106+
anchorView.removeFromSuperview()
107+
view.removeFromSuperview()
108+
}
109+
110+
func handlePan(recognizer: UIPanGestureRecognizer) {
111+
guard let swipeableView = swipeableView else { return }
112+
113+
let translation = recognizer.translationInView(containerView)
114+
let location = recognizer.locationInView(containerView)
115+
let velocity = recognizer.velocityInView(containerView)
116+
let movement = Movement(location: location, translation: translation, velocity: velocity)
117+
118+
switch recognizer.state {
119+
case .Began:
120+
guard case .Snapping(_) = state else { return }
121+
state = .Moving(location)
122+
swipeableView.didStart?(view: view, atLocation: location)
123+
case .Changed:
124+
guard case .Moving(_) = state else { return }
125+
state = .Moving(location)
126+
swipeableView.swiping?(view: view, atLocation: location, translation: translation)
127+
case .Ended, .Cancelled:
128+
guard case .Moving(_) = state else { return }
129+
if swipeableView.shouldSwipeView(view: view, movement: movement, swipeableView: swipeableView) {
130+
let directionVector = CGVector(point: translation.normalized * max(velocity.magnitude, swipeableView.minVelocityInPointPerSecond))
131+
state = .Swiping(location, directionVector)
132+
swipeableView.swipeView(view, location: location, directionVector: directionVector)
133+
} else {
134+
state = snappingStateAtContainerCenter()
135+
swipeableView.didCancel?(view: view)
136+
}
137+
swipeableView.didEnd?(view: view, atLocation: location)
138+
default:
139+
break
140+
}
141+
}
142+
143+
func handleTap(recognizer: UITapGestureRecognizer) {
144+
guard let swipeableView = swipeableView, topView = swipeableView.topView() else { return }
145+
146+
let location = recognizer.locationInView(containerView)
147+
swipeableView.didTap?(view: topView, atLocation: location)
148+
}
149+
150+
private func snapView(point: CGPoint) {
151+
snapBehavior = UISnapBehavior(item: view, snapToPoint: point)
152+
snapBehavior!.damping = 0.75
153+
addBehavior(snapBehavior)
154+
}
155+
156+
private func unsnapView() {
157+
guard let snapBehavior = snapBehavior else { return }
158+
removeBehavior(snapBehavior)
159+
}
160+
161+
private func attachView(toPoint point: CGPoint) {
162+
anchorView.center = point
163+
anchorView.backgroundColor = UIColor.blueColor()
164+
anchorView.hidden = true
165+
166+
// attach aView to anchorView
167+
let p = view.center
168+
viewToAnchorViewAttachmentBehavior = UIAttachmentBehavior(item: view, offsetFromCenter: UIOffset(horizontal: -(p.x - point.x), vertical: -(p.y - point.y)), attachedToItem: anchorView, offsetFromCenter: UIOffsetZero)
169+
viewToAnchorViewAttachmentBehavior!.length = 0
170+
171+
// attach anchorView to point
172+
anchorViewToPointAttachmentBehavior = UIAttachmentBehavior(item: anchorView, offsetFromCenter: UIOffsetZero, attachedToAnchor: point)
173+
anchorViewToPointAttachmentBehavior!.damping = 100
174+
anchorViewToPointAttachmentBehavior!.length = 0
175+
176+
addBehavior(viewToAnchorViewAttachmentBehavior!)
177+
addBehavior(anchorViewToPointAttachmentBehavior!)
178+
}
179+
180+
private func moveView(toPoint point: CGPoint) {
181+
guard let _ = viewToAnchorViewAttachmentBehavior, let toPoint = anchorViewToPointAttachmentBehavior else { return }
182+
toPoint.anchorPoint = point
183+
}
184+
185+
private func detachView() {
186+
guard let viewToAnchorViewAttachmentBehavior = viewToAnchorViewAttachmentBehavior, let anchorViewToPointAttachmentBehavior = anchorViewToPointAttachmentBehavior else { return }
187+
removeBehavior(viewToAnchorViewAttachmentBehavior)
188+
removeBehavior(anchorViewToPointAttachmentBehavior)
189+
}
190+
191+
private func pushView(fromPoint point: CGPoint, inDirection direction: CGVector) {
192+
guard let _ = viewToAnchorViewAttachmentBehavior, let anchorViewToPointAttachmentBehavior = anchorViewToPointAttachmentBehavior else { return }
193+
194+
removeBehavior(anchorViewToPointAttachmentBehavior)
195+
196+
pushBehavior = UIPushBehavior(items: [anchorView], mode: .Instantaneous)
197+
pushBehavior.pushDirection = direction
198+
addBehavior(pushBehavior)
199+
}
200+
201+
private func unpushView() {
202+
guard let pushBehavior = pushBehavior else { return }
203+
removeBehavior(pushBehavior)
204+
}
205+
206+
private func addBehavior(behavior: UIDynamicBehavior) {
207+
animator.addBehavior(behavior)
208+
}
209+
210+
private func removeBehavior(behavior: UIDynamicBehavior) {
211+
animator.removeBehavior(behavior)
212+
}
213+
214+
}

0 commit comments

Comments
 (0)