1
- //
2
- // DatePickerDialog.swift
3
- // DatePickerDialogExample
4
- //
5
- // Created by vinicius on 11/20/14.
6
- // Copyright (c) 2014 Squimer. All rights reserved.
7
- //
8
-
9
1
import UIKit
10
2
import QuartzCore
11
3
12
- protocol DatePickerDialogDelegate {
13
-
14
- func datePickerDialog( didSelect date: NSDate , from tag: String )
15
-
16
- }
17
-
18
4
class DatePickerDialog : UIView {
19
5
20
6
/* Consts */
21
- let backgroundAlpha : CGFloat = 0.5
22
- let animationDuration : NSTimeInterval = 0.25
23
- let cornerRadius : CGFloat = 8.0
7
+ private let kDatePickerDialogDefaultButtonHeight : CGFloat = 50
8
+ private let kDatePickerDialogDefaultButtonSpacerHeight : CGFloat = 1
9
+ private let kDatePickerDialogCornerRadius : CGFloat = 7
10
+ private let kDatePickerDialogCancelButtonTag : Int = 1
11
+ private let kDatePickerDialogDoneButtonTag : Int = 2
24
12
25
- /* IBOutlets */
26
- @IBOutlet weak var titleLabel : UILabel !
27
- @IBOutlet weak var datePicker : UIDatePicker !
13
+ /* Views */
14
+ private var dialogView : UIView !
15
+ private var titleLabel : UILabel !
16
+ private var datePicker : UIDatePicker !
17
+ private var cancelButton : UIButton !
18
+ private var doneButton : UIButton !
28
19
29
- /* Local vars */
30
- var datePickerTag : String = " "
31
- var delegate : DatePickerDialogDelegate ?
20
+ /* Vars */
21
+ private var title : String !
22
+ private var doneButtonTitle : String !
23
+ private var cancelButtonTitle : String !
24
+ private var defaultDate : NSDate !
25
+ private var datePickerMode : UIDatePickerMode !
26
+ private var callback : ( ( date: NSDate ) -> Void ) !
32
27
33
28
/* Overrides */
34
- override init ( frame: CGRect ) {
35
- super. init ( frame: frame)
36
-
37
- configureOverlay ( )
38
- configureNib ( )
29
+ override init ( ) {
30
+ super. init ( frame: CGRectMake ( 0 , 0 , UIScreen . mainScreen ( ) . bounds. size. width, UIScreen . mainScreen ( ) . bounds. size. height) )
39
31
40
- self . hidden = true
32
+ NSNotificationCenter . defaultCenter ( ) . addObserver ( self , selector : " deviceOrientationDidChange: " , name : UIDeviceOrientationDidChangeNotification , object : nil )
41
33
}
42
34
43
35
required init ( coder aDecoder: NSCoder ) {
44
36
super. init ( coder: aDecoder)
45
37
}
46
38
47
- /* IBActions */
48
- @ IBAction func cancelTapped ( sender : AnyObject ) {
49
- hidePicker ( )
39
+ /* Handle device orientation changes */
40
+ func deviceOrientationDidChange ( notification : NSNotification ) {
41
+ /* TODO */
50
42
}
51
43
52
- @IBAction func selectTapped( sender: AnyObject ) {
53
- hidePicker ( )
54
- if self . delegate != nil {
55
- self . delegate!. datePickerDialog ( didSelect: self . datePicker. date, from: self . datePickerTag)
44
+ /* Create the dialog view, and animate opening the dialog */
45
+ func show( #title: String, datePickerMode: UIDatePickerMode = . DateAndTime, callback: ( ( date: NSDate ) -> Void ) ) {
46
+ show ( title: title, doneButtonTitle: " Done " , cancelButtonTitle: " Cancel " , datePickerMode: datePickerMode, callback: callback)
47
+ }
48
+
49
+ func show( #title: String, do neButtonTitle: String, cancelButtonTitle: String, defaultDate: NSDate = NSDate( ) , datePickerMode: UIDatePickerMode = . DateAndTime, callback: ( ( date: NSDate ) -> Void ) ) {
50
+ self . title = title
51
+ self . doneButtonTitle = doneButtonTitle
52
+ self . cancelButtonTitle = cancelButtonTitle
53
+ self . datePickerMode = datePickerMode
54
+ self . callback = callback
55
+ self . defaultDate = defaultDate
56
+
57
+ self . dialogView = createContainerView ( )
58
+
59
+ self . dialogView!. layer. shouldRasterize = true
60
+ self . dialogView!. layer. rasterizationScale = UIScreen . mainScreen ( ) . scale
61
+
62
+ self . layer. shouldRasterize = true
63
+ self . layer. rasterizationScale = UIScreen . mainScreen ( ) . scale
64
+
65
+ self . dialogView!. layer. opacity = 0.5
66
+ self . dialogView!. layer. transform = CATransform3DMakeScale ( 1.3 , 1.3 , 1 )
67
+
68
+ self . backgroundColor = UIColor ( red: 0 , green: 0 , blue: 0 , alpha: 0 )
69
+
70
+ self . addSubview ( self . dialogView!)
71
+
72
+ /* Attached to the top most window (make sure we are using the right orientation) */
73
+ let interfaceOrientation = UIApplication . sharedApplication ( ) . statusBarOrientation
74
+
75
+ switch ( interfaceOrientation) {
76
+ case UIInterfaceOrientation . LandscapeLeft:
77
+ let t : Double = M_PI * 270 / 180
78
+ self . transform = CGAffineTransformMakeRotation ( CGFloat ( t) )
79
+ break
80
+
81
+ case UIInterfaceOrientation . LandscapeRight:
82
+ let t : Double = M_PI * 90 / 180
83
+ self . transform = CGAffineTransformMakeRotation ( CGFloat ( t) )
84
+ break
85
+
86
+ case UIInterfaceOrientation . PortraitUpsideDown:
87
+ let t : Double = M_PI * 180 / 180
88
+ self . transform = CGAffineTransformMakeRotation ( CGFloat ( t) )
89
+ break
90
+
91
+ default :
92
+ break
56
93
}
94
+
95
+ self . frame = CGRectMake ( 0 , 0 , self . frame. width, self . frame. size. height)
96
+ UIApplication . sharedApplication ( ) . windows. first!. addSubview ( self )
97
+
98
+ /* Anim */
99
+ UIView . animateWithDuration (
100
+ 0.2 ,
101
+ delay: 0 ,
102
+ options: UIViewAnimationOptions . CurveEaseInOut,
103
+ animations: { ( ) -> Void in
104
+ self . backgroundColor = UIColor ( red: 0 , green: 0 , blue: 0 , alpha: 0.4 )
105
+ self . dialogView!. layer. opacity = 1
106
+ self . dialogView!. layer. transform = CATransform3DMakeScale ( 1 , 1 , 1 )
107
+ } ,
108
+ completion: nil
109
+ )
57
110
}
58
111
59
- /* Helper functions */
60
- private func configureOverlay( ) {
61
- var overlayView = UIView ( frame: CGRectMake ( 0 , 0 , self . frame. size. width, self . frame. size. height) )
62
- overlayView. backgroundColor = UIColor . blackColor ( )
63
- overlayView. alpha = self . backgroundAlpha
64
- self . addSubview ( overlayView)
112
+ /* Dialog close animation then cleaning and removing the view from the parent */
113
+ private func close( ) {
114
+ let currentTransform = self . dialogView. layer. transform
115
+
116
+ let startRotation = ( self . valueForKeyPath ( " layer.transform.rotation.z " ) as? NSNumber ) ? as? Double ?? 0.0
117
+ let rotation = CATransform3DMakeRotation ( ( CGFloat) ( - startRotation + M_PI * 270 / 180 ) , 0 , 0 , 0 )
118
+
119
+ self . dialogView. layer. transform = CATransform3DConcat ( rotation, CATransform3DMakeScale ( 1 , 1 , 1 ) )
120
+ self . dialogView. layer. opacity = 1
121
+
122
+ UIView . animateWithDuration (
123
+ 0.2 ,
124
+ delay: 0 ,
125
+ options: UIViewAnimationOptions . TransitionNone,
126
+ animations: { ( ) -> Void in
127
+ self . backgroundColor = UIColor ( red: 0 , green: 0 , blue: 0 , alpha: 0 )
128
+ self . dialogView. layer. transform = CATransform3DConcat ( currentTransform, CATransform3DMakeScale ( 0.6 , 0.6 , 1 ) )
129
+ self . dialogView. layer. opacity = 0
130
+ } ) { ( finished: Bool ) -> Void in
131
+ for v in self . subviews {
132
+ v. removeFromSuperview ( )
133
+ }
134
+
135
+ self . removeFromSuperview ( )
136
+ }
65
137
}
66
138
67
- private func configureNib( ) {
68
- var nibContents = NSBundle . mainBundle ( ) . loadNibNamed ( " DatePickerDialog " , owner: self , options: nil )
69
- var pickerView = nibContents [ 0 ] as UIView
70
- pickerView. frame = CGRectMake ( 15 , ( self . frame. size. height / 2 ) - ( pickerView. frame. size. height / 2 ) - 16 , frame. size. width - 30 , pickerView. frame. size. height)
71
-
72
- //If is running iOS 7
73
- var c : AnyObject ? = objc_getClass ( " UIAlertController " . cStringUsingEncoding ( NSASCIIStringEncoding) )
74
- if c == nil {
75
- pickerView. frame. origin. x = 8
76
- }
139
+ /* Creates the container view here: create the dialog, then add the custom content and buttons */
140
+ private func createContainerView( ) -> UIView {
141
+ let screenSize = countScreenSize ( )
142
+ let dialogSize = CGSizeMake (
143
+ 300 ,
144
+ 230
145
+ + kDatePickerDialogDefaultButtonHeight
146
+ + kDatePickerDialogDefaultButtonSpacerHeight)
147
+
148
+ // For the black background
149
+ self . frame = CGRectMake ( 0 , 0 , screenSize. width, screenSize. height)
150
+
151
+ // This is the dialog's container; we attach the custom content and the buttons to this one
152
+ let dialogContainer = UIView ( frame: CGRectMake ( ( screenSize. width - dialogSize. width) / 2 , ( screenSize. height - dialogSize. height) / 2 , dialogSize. width, dialogSize. height) )
153
+
154
+ // First, we style the dialog to match the iOS8 UIAlertView >>>
155
+ let gradient : CAGradientLayer = CAGradientLayer ( layer: self . layer)
156
+ gradient. frame = dialogContainer. bounds
157
+ gradient. colors = [ UIColor ( red: 218 / 255 , green: 218 / 255 , blue: 218 / 255 , alpha: 1 ) . CGColor,
158
+ UIColor ( red: 233 / 255 , green: 233 / 255 , blue: 233 / 255 , alpha: 1 ) . CGColor,
159
+ UIColor ( red: 218 / 255 , green: 218 / 255 , blue: 218 / 255 , alpha: 1 ) . CGColor]
160
+
161
+ let cornerRadius = kDatePickerDialogCornerRadius
162
+ gradient. cornerRadius = cornerRadius
163
+ dialogContainer. layer. insertSublayer ( gradient, atIndex: 0 )
77
164
78
- /* Corners */
79
- pickerView. layer. cornerRadius = self . cornerRadius
165
+ dialogContainer. layer. cornerRadius = cornerRadius
166
+ dialogContainer. layer. borderColor = UIColor ( red: 198 / 255 , green: 198 / 255 , blue: 198 / 255 , alpha: 1 ) . CGColor
167
+ dialogContainer. layer. borderWidth = 1
168
+ dialogContainer. layer. shadowRadius = cornerRadius + 5
169
+ dialogContainer. layer. shadowOpacity = 0.1
170
+ dialogContainer. layer. shadowOffset = CGSizeMake ( 0 - ( cornerRadius + 5 ) / 2 , 0 - ( cornerRadius + 5 ) / 2 )
171
+ dialogContainer. layer. shadowColor = UIColor . blackColor ( ) . CGColor
172
+ dialogContainer. layer. shadowPath = UIBezierPath ( roundedRect: dialogContainer. bounds, cornerRadius: dialogContainer. layer. cornerRadius) . CGPath
80
173
81
- /* Shadow */
82
- self . layer. masksToBounds = false
83
- self . layer. cornerRadius = self . cornerRadius
84
- self . layer. shadowOffset = CGSizeMake ( - 1 , 1 )
85
- self . layer. shadowRadius = 10
86
- self . layer. shadowOpacity = 0.5
174
+ // There is a line above the button
175
+ let lineView = UIView ( frame: CGRectMake ( 0 , dialogContainer. bounds. size. height - kDatePickerDialogDefaultButtonHeight - kDatePickerDialogDefaultButtonSpacerHeight, dialogContainer. bounds. size. width, kDatePickerDialogDefaultButtonSpacerHeight) )
176
+ lineView. backgroundColor = UIColor ( red: 198 / 255 , green: 198 / 255 , blue: 198 / 255 , alpha: 1 )
177
+ dialogContainer. addSubview ( lineView)
178
+ // ˆˆˆ
87
179
88
- self . addSubview ( pickerView)
180
+ //Title
181
+ self . titleLabel = UILabel ( frame: CGRectMake ( 10 , 10 , 280 , 30 ) )
182
+ self . titleLabel. textAlignment = NSTextAlignment . Center
183
+ self . titleLabel. font = UIFont . boldSystemFontOfSize ( 17 )
184
+ self . titleLabel. text = self . title
185
+ dialogContainer. addSubview ( self . titleLabel)
186
+
187
+ self . datePicker = UIDatePicker ( frame: CGRectMake ( 0 , 30 , 0 , 0 ) )
188
+ self . datePicker. autoresizingMask = UIViewAutoresizing . FlexibleRightMargin
189
+ self . datePicker. frame. size. width = 300
190
+ self . datePicker. datePickerMode = self . datePickerMode
191
+ self . datePicker. date = self . defaultDate
192
+ dialogContainer. addSubview ( self . datePicker)
193
+
194
+ // Add the buttons
195
+ addButtonsToView ( dialogContainer)
196
+
197
+ return dialogContainer
89
198
}
90
199
91
- func showPickerWithTag( tag: String , title: String ) {
92
- self . titleLabel. text = title
93
- self . datePickerTag = tag
94
- self . hidden = false
95
- self . alpha = 0.0
96
- UIView . animateWithDuration ( self . animationDuration, animations: {
97
- self . alpha = 1.0
98
- } , completion: nil )
200
+ /* Add buttons to container */
201
+ private func addButtonsToView( container: UIView ) {
202
+ let buttonWidth = container. bounds. size. width / 2
203
+
204
+ self . cancelButton = UIButton . buttonWithType ( UIButtonType . Custom) as UIButton
205
+ self . cancelButton. frame = CGRectMake (
206
+ 0 ,
207
+ container. bounds. size. height - kDatePickerDialogDefaultButtonHeight,
208
+ buttonWidth,
209
+ kDatePickerDialogDefaultButtonHeight
210
+ )
211
+ self . cancelButton. tag = kDatePickerDialogCancelButtonTag
212
+ self . cancelButton. setTitle ( self . cancelButtonTitle, forState: UIControlState . Normal)
213
+ self . cancelButton. setTitleColor ( UIColor ( red: 0 , green: 0.5 , blue: 1 , alpha: 1 ) , forState: UIControlState . Normal)
214
+ self . cancelButton. setTitleColor ( UIColor ( red: 0.2 , green: 0.2 , blue: 0.2 , alpha: 0.5 ) , forState: UIControlState . Highlighted)
215
+ self . cancelButton. titleLabel!. font = UIFont . boldSystemFontOfSize ( 14 )
216
+ self . cancelButton. layer. cornerRadius = kDatePickerDialogCornerRadius
217
+ self . cancelButton. addTarget ( self , action: " buttonTapped: " , forControlEvents: UIControlEvents . TouchUpInside)
218
+ container. addSubview ( self . cancelButton)
219
+
220
+ self . doneButton = UIButton . buttonWithType ( UIButtonType . Custom) as UIButton
221
+ self . doneButton. frame = CGRectMake (
222
+ buttonWidth,
223
+ container. bounds. size. height - kDatePickerDialogDefaultButtonHeight,
224
+ buttonWidth,
225
+ kDatePickerDialogDefaultButtonHeight
226
+ )
227
+ self . doneButton. tag = kDatePickerDialogDoneButtonTag
228
+ self . doneButton. setTitle ( self . doneButtonTitle, forState: UIControlState . Normal)
229
+ self . doneButton. setTitleColor ( UIColor ( red: 0 , green: 0.5 , blue: 1 , alpha: 1 ) , forState: UIControlState . Normal)
230
+ self . doneButton. setTitleColor ( UIColor ( red: 0.2 , green: 0.2 , blue: 0.2 , alpha: 0.5 ) , forState: UIControlState . Highlighted)
231
+ self . doneButton. titleLabel!. font = UIFont . boldSystemFontOfSize ( 14 )
232
+ self . doneButton. layer. cornerRadius = kDatePickerDialogCornerRadius
233
+ self . doneButton. addTarget ( self , action: " buttonTapped: " , forControlEvents: UIControlEvents . TouchUpInside)
234
+ container. addSubview ( self . doneButton)
235
+ }
236
+
237
+ func buttonTapped( sender: UIButton ! ) {
238
+ if sender. tag == kDatePickerDialogDoneButtonTag {
239
+ self . callback ( date: self . datePicker. date)
240
+ } else if sender. tag == kDatePickerDialogCancelButtonTag {
241
+ //There's nothing do to here \o\
242
+ }
243
+
244
+ close ( )
99
245
}
100
246
101
- func hidePicker( ) {
102
- UIView . animateWithDuration ( self . animationDuration, animations: { ( ) -> Void in
103
- self . alpha = 0.0
104
- } ) { ( value: Bool ) -> Void in
105
- self . hidden = true
247
+ /* Helper function: count and return the screen's size */
248
+ func countScreenSize( ) -> CGSize {
249
+ var screenWidth = UIScreen . mainScreen ( ) . bounds. size. width
250
+ var screenHeight = UIScreen . mainScreen ( ) . bounds. size. height
251
+
252
+ let interfaceOrientaion = UIApplication . sharedApplication ( ) . statusBarOrientation
253
+
254
+ if UIInterfaceOrientationIsLandscape ( interfaceOrientaion) {
255
+ let tmp = screenWidth
256
+ screenWidth = screenHeight
257
+ screenHeight = tmp
106
258
}
259
+
260
+ return CGSizeMake ( screenWidth, screenHeight)
107
261
}
108
262
109
- }
263
+ }
0 commit comments