1
+ //
2
+ // DDPageControl.m
3
+ // DDPageControl
4
+ //
5
+ // Created by Damien DeVille on 1/14/11.
6
+ // Copyright 2011 Snappy Code. All rights reserved.
7
+ //
8
+
9
+ #import " DDPageControl.h"
10
+
11
+
12
+ #define kDotDiameter 4 .0f
13
+ #define kDotSpace 12 .0f
14
+
15
+ @interface DDPageControl (Private)
16
+
17
+ - (void )callTargetForValueChanged ;
18
+
19
+ @end
20
+
21
+
22
+
23
+ @implementation DDPageControl
24
+
25
+ @synthesize numberOfPages ;
26
+ @synthesize currentPage ;
27
+ @synthesize hidesForSinglePage ;
28
+ @synthesize defersCurrentPageDisplay ;
29
+
30
+ @synthesize type ;
31
+ @synthesize onColor ;
32
+ @synthesize offColor ;
33
+ @synthesize indicatorDiameter ;
34
+ @synthesize indicatorSpace ;
35
+
36
+ #pragma mark -
37
+ #pragma mark Initializers - dealloc
38
+
39
+ - (id )initWithType : (DDPageControlType)theType
40
+ {
41
+ self = [self initWithFrame: CGRectZero ] ;
42
+ [self setType: theType] ;
43
+ return self ;
44
+ }
45
+
46
+ - (id )init
47
+ {
48
+ self = [self initWithFrame: CGRectZero ] ;
49
+ return self ;
50
+ }
51
+
52
+ - (id )initWithFrame : (CGRect )frame
53
+ {
54
+ if ((self = [super initWithFrame: CGRectZero ]))
55
+ {
56
+ self.backgroundColor = [UIColor clearColor ] ;
57
+ }
58
+ return self ;
59
+ }
60
+
61
+ - (void )dealloc
62
+ {
63
+ [onColor release ], onColor = nil ;
64
+ [offColor release ], offColor = nil ;
65
+
66
+ [super dealloc ] ;
67
+ }
68
+
69
+
70
+ #pragma mark -
71
+ #pragma mark drawRect
72
+
73
+ - (void )drawRect : (CGRect )rect
74
+ {
75
+ // get the current context
76
+ CGContextRef context = UIGraphicsGetCurrentContext () ;
77
+
78
+ // save the context
79
+ CGContextSaveGState (context) ;
80
+
81
+ // allow antialiasing
82
+ CGContextSetAllowsAntialiasing (context, TRUE ) ;
83
+
84
+ // get the caller's diameter if it has been set or use the default one
85
+ CGFloat diameter = (indicatorDiameter > 0 ) ? indicatorDiameter : kDotDiameter ;
86
+ CGFloat space = (indicatorSpace > 0 ) ? indicatorSpace : kDotSpace ;
87
+
88
+ // geometry
89
+ CGRect currentBounds = self.bounds ;
90
+ CGFloat dotsWidth = self.numberOfPages * diameter + MAX (0 , self.numberOfPages - 1 ) * space ;
91
+ CGFloat x = CGRectGetMidX (currentBounds) - dotsWidth / 2 ;
92
+ CGFloat y = CGRectGetMidY (currentBounds) - diameter / 2 ;
93
+
94
+ // get the caller's colors it they have been set or use the defaults
95
+ CGColorRef onColorCG = onColor ? onColor.CGColor : [UIColor colorWithWhite: 1 .0f alpha: 1 .0f ].CGColor ;
96
+ CGColorRef offColorCG = offColor ? offColor.CGColor : [UIColor colorWithWhite: 0 .7f alpha: 0 .5f ].CGColor ;
97
+
98
+ // actually draw the dots
99
+ for (int i = 0 ; i < numberOfPages ; i++)
100
+ {
101
+ CGRect dotRect = CGRectMake (x, y, diameter, diameter) ;
102
+
103
+ if (i == currentPage)
104
+ {
105
+ if (type == DDPageControlTypeOnFullOffFull || type == DDPageControlTypeOnFullOffEmpty)
106
+ {
107
+ CGContextSetFillColorWithColor (context, onColorCG) ;
108
+ CGContextFillEllipseInRect (context, CGRectInset (dotRect, -1 .0f , -1 .0f )) ;
109
+ }
110
+ else
111
+ {
112
+ CGContextSetStrokeColorWithColor (context, onColorCG) ;
113
+ CGContextStrokeEllipseInRect (context, dotRect) ;
114
+ }
115
+ }
116
+ else
117
+ {
118
+ if (type == DDPageControlTypeOnEmptyOffEmpty || type == DDPageControlTypeOnFullOffEmpty)
119
+ {
120
+ CGContextSetStrokeColorWithColor (context, offColorCG) ;
121
+ CGContextStrokeEllipseInRect (context, dotRect) ;
122
+ }
123
+ else
124
+ {
125
+ CGContextSetFillColorWithColor (context, offColorCG) ;
126
+ CGContextFillEllipseInRect (context, CGRectInset (dotRect, -1 .0f , -1 .0f )) ;
127
+ }
128
+ }
129
+
130
+ x += diameter + space ;
131
+ }
132
+
133
+ // restore the context
134
+ CGContextRestoreGState (context) ;
135
+ }
136
+
137
+
138
+ #pragma mark -
139
+ #pragma mark Accessors
140
+
141
+ - (void )setCurrentPage : (NSInteger )pageNumber
142
+ {
143
+ // no need to update in that case
144
+ if (currentPage == pageNumber)
145
+ return ;
146
+
147
+ // determine if the page number is in the available range
148
+ currentPage = MIN (MAX (0 , pageNumber), numberOfPages - 1 ) ;
149
+
150
+ // in case we do not defer the page update, we redraw the view
151
+ if (self.defersCurrentPageDisplay == NO )
152
+ [self setNeedsDisplay ] ;
153
+ }
154
+
155
+ - (void )setNumberOfPages : (NSInteger )numOfPages
156
+ {
157
+ // make sure the number of pages is positive
158
+ numberOfPages = MAX (0 , numOfPages) ;
159
+
160
+ // we then need to update the current page
161
+ currentPage = MIN (MAX (0 , currentPage), numberOfPages - 1 ) ;
162
+
163
+ // correct the bounds accordingly
164
+ self.bounds = self.bounds ;
165
+
166
+ // we need to redraw
167
+ [self setNeedsDisplay ] ;
168
+
169
+ // depending on the user preferences, we hide the page control with a single element
170
+ if (hidesForSinglePage && (numOfPages < 2 ))
171
+ [self setHidden: YES ] ;
172
+ else
173
+ [self setHidden: NO ] ;
174
+ }
175
+
176
+ - (void )setHidesForSinglePage : (BOOL )hide
177
+ {
178
+ hidesForSinglePage = hide ;
179
+
180
+ // depending on the user preferences, we hide the page control with a single element
181
+ if (hidesForSinglePage && (numberOfPages < 2 ))
182
+ [self setHidden: YES ] ;
183
+ }
184
+
185
+ - (void )setDefersCurrentPageDisplay : (BOOL )defers
186
+ {
187
+ defersCurrentPageDisplay = defers ;
188
+ }
189
+
190
+ - (void )setType : (DDPageControlType)aType
191
+ {
192
+ type = aType ;
193
+
194
+ [self setNeedsDisplay ] ;
195
+ }
196
+
197
+ - (void )setOnColor : (UIColor *)aColor
198
+ {
199
+ [aColor retain ] ;
200
+ [onColor release ] ;
201
+ onColor = aColor ;
202
+
203
+ [self setNeedsDisplay ] ;
204
+ }
205
+
206
+ - (void )setOffColor : (UIColor *)aColor
207
+ {
208
+ [aColor retain ] ;
209
+ [offColor release ] ;
210
+ offColor = aColor ;
211
+
212
+ [self setNeedsDisplay ] ;
213
+ }
214
+
215
+ - (void )setIndicatorDiameter : (CGFloat )aDiameter
216
+ {
217
+ indicatorDiameter = aDiameter ;
218
+
219
+ // correct the bounds accordingly
220
+ self.bounds = self.bounds ;
221
+
222
+ [self setNeedsDisplay ] ;
223
+ }
224
+
225
+ - (void )setIndicatorSpace : (CGFloat )aSpace
226
+ {
227
+ indicatorSpace = aSpace ;
228
+
229
+ // correct the bounds accordingly
230
+ self.bounds = self.bounds ;
231
+
232
+ [self setNeedsDisplay ] ;
233
+ }
234
+
235
+ - (void )setFrame : (CGRect )aFrame
236
+ {
237
+ // we do not allow the caller to modify the size struct in the frame so we compute it
238
+ aFrame.size = [self sizeForNumberOfPages: numberOfPages] ;
239
+ super.frame = aFrame ;
240
+ }
241
+
242
+ - (void )setBounds : (CGRect )aBounds
243
+ {
244
+ // we do not allow the caller to modify the size struct in the bounds so we compute it
245
+ aBounds.size = [self sizeForNumberOfPages: numberOfPages] ;
246
+ super.bounds = aBounds ;
247
+ }
248
+
249
+
250
+
251
+ #pragma mark -
252
+ #pragma mark UIPageControl methods
253
+
254
+ - (void )updateCurrentPageDisplay
255
+ {
256
+ // ignores this method if the value of defersPageIndicatorUpdate is NO
257
+ if (self.defersCurrentPageDisplay == NO )
258
+ return ;
259
+
260
+ // in case it is YES, we redraw the view (that will update the page control to the correct page)
261
+ [self setNeedsDisplay ] ;
262
+ }
263
+
264
+ - (CGSize )sizeForNumberOfPages : (NSInteger )pageCount
265
+ {
266
+ CGFloat diameter = (indicatorDiameter > 0 ) ? indicatorDiameter : kDotDiameter ;
267
+ CGFloat space = (indicatorSpace > 0 ) ? indicatorSpace : kDotSpace ;
268
+
269
+ return CGSizeMake (pageCount * diameter + (pageCount - 1 ) * space + 44 .0f , MAX (44 .0f , diameter + 4 .0f )) ;
270
+ }
271
+
272
+
273
+ #pragma mark -
274
+ #pragma mark Touches handlers
275
+
276
+ - (void )touchesEnded : (NSSet *)touches withEvent : (UIEvent *)event
277
+ {
278
+ // get the touch location
279
+ UITouch *theTouch = [touches anyObject ] ;
280
+ CGPoint touchLocation = [theTouch locationInView: self ] ;
281
+
282
+ // check whether the touch is in the right or left hand-side of the control
283
+ if (touchLocation.x < (self.bounds .size .width / 2 ))
284
+ self.currentPage = MAX (self.currentPage - 1 , 0 ) ;
285
+ else
286
+ self.currentPage = MIN (self.currentPage + 1 , numberOfPages - 1 ) ;
287
+
288
+ // call the target to alert that the value has changed
289
+ [self callTargetForValueChanged ] ;
290
+ }
291
+
292
+
293
+ #pragma mark -
294
+ #pragma mark Target calls
295
+
296
+ - (void )callTargetForValueChanged
297
+ {
298
+ // we get all targets for this object
299
+ NSSet *allTargets = [self allTargets ] ;
300
+ NSArray *allActions ;
301
+ for (id target in allTargets)
302
+ {
303
+ // get all actions associated with this target and the control event UIControlEventValueChanged
304
+ allActions = [self actionsForTarget: target forControlEvent: UIControlEventValueChanged] ;
305
+ for (NSString *action in allActions)
306
+ {
307
+ // perform the selector (action) on the target
308
+ [target performSelector: NSSelectorFromString (action) withObject: self ] ;
309
+ }
310
+ }
311
+ }
312
+
313
+ @end
0 commit comments