-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBasePanel.swift
More file actions
262 lines (222 loc) · 10.4 KB
/
Copy pathBasePanel.swift
File metadata and controls
262 lines (222 loc) · 10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
//
// BasePanel.swift
// MKWS
//
// Created by Alex Sims on 15/04/2015.
// Copyright (c) 2015 Alexander Sims. All rights reserved.
//
import UIKit
// Need to use Objc protocol as swift doesn't allow optional delegates
@objc protocol BasePanelDelegate {
optional func basePanelDidSelectRowAtIndex(index:Int)
optional func basePanelDidConfirmDate(date:NSDate)
optional func basePanelWillClose()
optional func basePanelWillOpen()
}
// conforms to the base panel delegate
class BasePanel: NSObject, BasePanelTableViewControllerDelegate {
let container:UIView = UIView()
let blackOverlay:UIView = UIView()
let title:UILabel = UILabel()
let tableViewController:BasePanelTableViewController = BasePanelTableViewController()
var originView:UIView?
var picker:UIDatePicker?
var confirmDate:UIButton?
var panelWidth:CGFloat!
var panelHeight:CGFloat!
var tabBarHeight:CGFloat!
var screenHeight:CGFloat!
var topInset:CGFloat = 50
var animator:UIDynamicAnimator!
var delegate:BasePanelDelegate?
var isOpen:Bool = false
var isPickerView:Bool = false
var aboveView:UIView?
// Constructor
override init()
{
super.init()
}
// Base initialiser
// Initialises a new Base Panel object and binds it to the source view with a list of items to
// be rendered in its tableView delegate. We also define any gesture recognisers for the panel here
// We set items to have a default of empty array here
init(sourceView: UIView, items:Array<String> = Array<String>(), aboveView: UIView)
{
super.init()
// Bind the source view and set the items for the delegate
originView = sourceView
self.aboveView = aboveView
tableViewController.tableData = items
// Initialise a new animator
animator = UIDynamicAnimator(referenceView: originView!)
// Style the panel
initBasePanel()
// Configure gesture recognisers here
let hidePanelRecogniser:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action:"handleSwipe:")
hidePanelRecogniser.direction = UISwipeGestureRecognizerDirection.Down
//let showPanelRecogniser:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action:"handleSwipe:")
//showPanelRecogniser.direction = UISwipeGestureRecognizerDirection.Up
originView?.addGestureRecognizer(hidePanelRecogniser)
//originView?.addGestureRecognizer(showPanelRecogniser)
}
// Set new items for the tableView controller delegate
func setItems(items:Array<String>)
{
tableViewController.tableData = items
tableViewController.tableView.reloadData()
}
// Style the base panel, setting its height relative to the source view so that it only takes up just
// under half of the display.
func initBasePanel()
{
// Define the bounds of the frame
panelWidth = originView!.frame.size.width
panelHeight = originView!.frame.size.height * 0.55
screenHeight = originView!.frame.size.height
tabBarHeight = tabBarHeight == nil ? 50 : tabBarHeight
// Set the frame for the container of this view based on the parent
container.frame = CGRectMake(0, screenHeight, panelWidth, panelHeight)
container.backgroundColor = UIColor(red: 30/255, green: 30/255, blue: 42/255, alpha: 1.0)
container.clipsToBounds = true
originView?.insertSubview(container, aboveSubview:aboveView!)
/*
// Set the blur view
let blurView: UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Light))
blurView.frame = container.bounds
container.addSubview(blurView)
*/
// Set up the table view and add it to the view
tableViewController.delegate = self
tableViewController.tableView.frame = container.bounds
tableViewController.tableView.clipsToBounds = false
tableViewController.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine
tableViewController.tableView.backgroundColor = UIColor.clearColor()
tableViewController.tableView.scrollsToTop = false
tableViewController.tableView.contentInset = UIEdgeInsetsMake(topInset, 0, 0, 0)
tableViewController.tableView.reloadData()
// Theme the table
tableViewController.tableView.backgroundColor = UIColor(red: 30/255, green: 30/255, blue: 42/255, alpha: 1.0)
tableViewController.tableView.separatorColor = UIColor(red: 41/255, green: 45/255, blue: 56/255, alpha: 1.0)
// Append the tableViewController delegate to this view
container.addSubview(tableViewController.tableView)
// Create the picker and hide it by default
picker = UIDatePicker(frame: CGRectMake(0, 60, container.frame.size.width, container.frame.size.height))
container.addSubview(picker!)
picker!.hidden = true
// Theme the data picker
picker?.backgroundColor = UIColor(red: 30/255, green: 30/255, blue: 42/255, alpha: 1.0)
picker?.setValue(UIColor.whiteColor(), forKeyPath: "textColor")
// Create the confirm button and hide it by default
confirmDate = UIButton(frame: CGRectMake(0, container.frame.height-65, container.frame.width, 65))
confirmDate?.setTitle("Confirm", forState: UIControlState.Normal)
confirmDate?.backgroundColor = UIColor(red: 2/255, green: 192/255, blue: 77/255, alpha: 1)
confirmDate?.titleLabel?.font.fontWithSize(24)
confirmDate?.addTarget(self, action: "basePanelDidSelectDate", forControlEvents: UIControlEvents.TouchUpInside)
container.addSubview(confirmDate!)
confirmDate?.hidden = true
// Build the title bar
let titleBar = UIView(frame: CGRectMake(0, 0, originView!.frame.width, 50))
titleBar.backgroundColor = UIColor(red: 34/255, green: 80/255, blue: 212/255, alpha: 0.98)
container.addSubview(titleBar)
// Set the title
title.frame = CGRectMake(0, 0, titleBar.frame.width, titleBar.frame.height)
title.textAlignment = NSTextAlignment.Center
title.textColor = UIColor.whiteColor()
titleBar.addSubview(title)
}
// Notifies the delegate and handles if panel should open or close
func handleSwipe(recogniser:UISwipeGestureRecognizer)
{
let direction = recogniser.direction
switch(direction)
{
case UISwipeGestureRecognizerDirection.Down:
showBasePanel(false)
delegate?.basePanelWillClose?()
default:
showBasePanel(true)
delegate?.basePanelWillOpen?()
}
}
// Define the animators properties for the view
func showBasePanel(open:Bool)
{
animator.removeAllBehaviors()
isOpen = open
// Define constants to be plugged into animator
let gravityY:CGFloat = (open) ? -8.0 : 6.0
let boundaryY:CGFloat = panelHeight
let boundaryX:CGFloat = panelWidth
// animator behaviours
let gravityBehavior:UIGravityBehavior = UIGravityBehavior(items: [container])
let collisionBehavior:UICollisionBehavior = UICollisionBehavior(items:[container])
let panelBehavior:UIDynamicItemBehavior = UIDynamicItemBehavior(items:[container])
// Set the behvaiours
panelBehavior.allowsRotation = false
panelBehavior.elasticity = 0.3
// Set collision behaviours
collisionBehavior.addBoundaryWithIdentifier("upperBoundary", fromPoint: CGPointMake(0, screenHeight - panelHeight - tabBarHeight), toPoint: CGPointMake(boundaryX, screenHeight - panelHeight - tabBarHeight))
collisionBehavior.addBoundaryWithIdentifier("lowerBoundary", fromPoint: CGPointMake(0, screenHeight+panelHeight + tabBarHeight), toPoint: CGPointMake(boundaryX, screenHeight+panelHeight + tabBarHeight))
gravityBehavior.gravityDirection = CGVectorMake(0, gravityY)
// set the animator behvaiours
animator.addBehavior(gravityBehavior)
animator.addBehavior(panelBehavior)
animator.addBehavior(collisionBehavior)
// Handle the black overlay
let tapGestureRecogniser:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "handleTap:")
blackOverlay.frame = CGRectMake(0, 0, originView!.frame.size.width, originView!.frame.size.height)
blackOverlay.userInteractionEnabled = true
blackOverlay.addGestureRecognizer(tapGestureRecogniser)
if open
{
blackOverlay.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0)
originView?.insertSubview(blackOverlay, belowSubview: container)
UIView.animateWithDuration(0.5, animations: { () -> Void in
self.blackOverlay.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5)
})
} else {
UIView.animateWithDuration(0.75, animations: { () -> Void in
self.blackOverlay.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0)
}) { (completed:Bool) -> Void in
if(completed)
{
self.blackOverlay.removeFromSuperview()
}
}
}
// Determine if we're using a picker view
if isPickerView
{
picker!.hidden = false
confirmDate!.hidden = false
tableViewController.tableView.hidden = true
}
else
{
picker!.hidden = true
confirmDate!.hidden = true
tableViewController.tableView.hidden = false
}
}
func handleTap(sender: UIView)
{
showBasePanel(false)
}
// Update the title
func setTitle(newTitle: String)
{
title.text = newTitle
}
// Notify the delegate that a new date has been selected
func basePanelDidSelectDate()
{
if let date:NSDate = picker?.date {
delegate?.basePanelDidConfirmDate!(date)
}
}
// Delegate method to get the selected data
func basePanelDidSelectRow(indexPath: NSIndexPath) {
delegate?.basePanelDidSelectRowAtIndex!(indexPath.row)
}
}