ActionSheetDistancePicker 2.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. //
  2. //Copyright (c) 2011, Tim Cinel
  3. //All rights reserved.
  4. //
  5. //Redistribution and use in source and binary forms, with or without
  6. //modification, are permitted provided that the following conditions are met:
  7. //* Redistributions of source code must retain the above copyright
  8. //notice, this list of conditions and the following disclaimer.
  9. //* Redistributions in binary form must reproduce the above copyright
  10. //notice, this list of conditions and the following disclaimer in the
  11. //documentation and/or other materials provided with the distribution.
  12. //* Neither the name of the <organization> nor the
  13. //names of its contributors may be used to endorse or promote products
  14. //derived from this software without specific prior written permission.
  15. //
  16. //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  17. //ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. //WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. //DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  20. //DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. //(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. //ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. //(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. //
  27. #import "ActionSheetDistancePicker.h"
  28. #import <objc/message.h>
  29. @interface ActionSheetDistancePicker()
  30. @property (nonatomic, strong) NSString *bigUnitString;
  31. @property (nonatomic, assign) NSInteger selectedBigUnit;
  32. @property (nonatomic, assign) NSInteger bigUnitMax;
  33. @property (nonatomic, assign) NSInteger bigUnitDigits;
  34. @property (nonatomic, strong) NSString *smallUnitString;
  35. @property (nonatomic, assign) NSInteger selectedSmallUnit;
  36. @property (nonatomic, assign) NSInteger smallUnitMax;
  37. @property (nonatomic, assign) NSInteger smallUnitDigits;
  38. @end
  39. @implementation ActionSheetDistancePicker
  40. + (instancetype)showPickerWithTitle:(NSString *)title bigUnitString:(NSString *)bigUnitString bigUnitMax:(NSInteger)bigUnitMax selectedBigUnit:(NSInteger)selectedBigUnit smallUnitString:(NSString *)smallUnitString smallUnitMax:(NSInteger)smallUnitMax selectedSmallUnit:(NSInteger)selectedSmallUnit target:(id)target action:(SEL)action origin:(id)origin {
  41. ActionSheetDistancePicker *picker = [[ActionSheetDistancePicker alloc] initWithTitle:title bigUnitString:bigUnitString bigUnitMax:bigUnitMax selectedBigUnit:selectedBigUnit smallUnitString:smallUnitString smallUnitMax:smallUnitMax selectedSmallUnit:selectedSmallUnit target:target action:action origin:origin];
  42. [picker showActionSheetPicker];
  43. return picker;
  44. }
  45. - (instancetype)initWithTitle:(NSString *)title bigUnitString:(NSString *)bigUnitString bigUnitMax:(NSInteger)bigUnitMax selectedBigUnit:(NSInteger)selectedBigUnit smallUnitString:(NSString *)smallUnitString smallUnitMax:(NSInteger)smallUnitMax selectedSmallUnit:(NSInteger)selectedSmallUnit target:(id)target action:(SEL)action origin:(id)origin {
  46. self = [super initWithTarget:target successAction:action cancelAction:nil origin:origin];
  47. if (self) {
  48. self.title = title;
  49. self.bigUnitString = bigUnitString;
  50. self.bigUnitMax = bigUnitMax;
  51. self.selectedBigUnit = selectedBigUnit;
  52. self.smallUnitString = smallUnitString;
  53. self.smallUnitMax = smallUnitMax;
  54. self.selectedSmallUnit = selectedSmallUnit;
  55. self.bigUnitDigits = [[NSString stringWithFormat:@"%li", (long)self.bigUnitMax] length];
  56. self.smallUnitDigits = [[NSString stringWithFormat:@"%li", (long)self.smallUnitMax] length];
  57. }
  58. return self;
  59. }
  60. + (instancetype)showPickerWithTitle:(NSString *)title bigUnitString:(NSString *)bigUnitString bigUnitMax:(NSInteger)bigUnitMax selectedBigUnit:(NSInteger)selectedBigUnit smallUnitString:(NSString *)smallUnitString smallUnitMax:(NSInteger)smallUnitMax selectedSmallUnit:(NSInteger)selectedSmallUnit target:(id)target action:(SEL)action origin:(id)origin cancelAction:(SEL)cancelAction
  61. {
  62. ActionSheetDistancePicker *picker = [[ActionSheetDistancePicker alloc] initWithTitle:title bigUnitString:bigUnitString bigUnitMax:bigUnitMax selectedBigUnit:selectedBigUnit smallUnitString:smallUnitString smallUnitMax:smallUnitMax selectedSmallUnit:selectedSmallUnit target:target action:action origin:origin cancelAction:cancelAction];
  63. [picker showActionSheetPicker];
  64. return picker;
  65. }
  66. - (instancetype)initWithTitle:(NSString *)title bigUnitString:(NSString *)bigUnitString bigUnitMax:(NSInteger)bigUnitMax selectedBigUnit:(NSInteger)selectedBigUnit smallUnitString:(NSString *)smallUnitString smallUnitMax:(NSInteger)smallUnitMax selectedSmallUnit:(NSInteger)selectedSmallUnit target:(id)target action:(SEL)action origin:(id)origin cancelAction:(SEL)cancelAction
  67. {
  68. self = [super initWithTarget:target successAction:action cancelAction:cancelAction origin:origin];
  69. if (self) {
  70. self.title = title;
  71. self.bigUnitString = bigUnitString;
  72. self.bigUnitMax = bigUnitMax;
  73. self.selectedBigUnit = selectedBigUnit;
  74. self.smallUnitString = smallUnitString;
  75. self.smallUnitMax = smallUnitMax;
  76. self.selectedSmallUnit = selectedSmallUnit;
  77. self.bigUnitDigits = [[NSString stringWithFormat:@"%li", (long)self.bigUnitMax] length];
  78. self.smallUnitDigits = [[NSString stringWithFormat:@"%li", (long)self.smallUnitMax] length];
  79. }
  80. return self;
  81. }
  82. - (UIView *)configuredPickerView {
  83. CGRect distancePickerFrame = CGRectMake(0, 40, self.viewSize.width, 216);
  84. DistancePickerView *picker = [[DistancePickerView alloc] initWithFrame:distancePickerFrame];
  85. picker.delegate = self;
  86. picker.dataSource = self;
  87. picker.showsSelectionIndicator = YES;
  88. // [picker addLabel:self.bigUnitString forComponent:(NSUInteger) (self.bigUnitDigits - 1) forLongestString:nil];
  89. // [picker addLabel:self.smallUnitString forComponent:(NSUInteger) (self.bigUnitDigits + self.smallUnitDigits - 1)
  90. // forLongestString:nil];
  91. NSInteger unitSubtract = 0;
  92. NSInteger currentDigit = 0;
  93. for (int i = 0; i < self.bigUnitDigits; ++i) {
  94. NSInteger factor = (int)pow((double)10, (double)(self.bigUnitDigits - (i+1)));
  95. currentDigit = (( self.selectedBigUnit - unitSubtract ) / factor ) ;
  96. [picker selectRow:currentDigit inComponent:i animated:NO];
  97. unitSubtract += currentDigit * factor;
  98. }
  99. unitSubtract = 0;
  100. for (NSInteger i = self.bigUnitDigits + 1; i < self.bigUnitDigits + self.smallUnitDigits + 1; ++i) {
  101. NSInteger factor = (int)pow((double)10, (double)(self.bigUnitDigits + self.smallUnitDigits + 1 - (i+1)));
  102. currentDigit = (( self.selectedSmallUnit - unitSubtract ) / factor ) ;
  103. [picker selectRow:currentDigit inComponent:i animated:NO];
  104. unitSubtract += currentDigit * factor;
  105. }
  106. //need to keep a reference to the picker so we can clear the DataSource / Delegate when dismissing
  107. self.pickerView = picker;
  108. return picker;
  109. }
  110. - (void)notifyTarget:(id)target didSucceedWithAction:(SEL)action origin:(id)origin {
  111. NSInteger bigUnits = 0;
  112. NSInteger smallUnits = 0;
  113. DistancePickerView *picker = (DistancePickerView *)self.pickerView;
  114. for (int i = 0; i < self.bigUnitDigits; ++i)
  115. bigUnits += [picker selectedRowInComponent:i] * (int)pow((double)10, (double)(self.bigUnitDigits - (i + 1)));
  116. for (NSInteger i = self.bigUnitDigits + 1; i < self.bigUnitDigits + self.smallUnitDigits + 1; ++i)
  117. smallUnits += [picker selectedRowInComponent:i] * (int)pow((double)10, (double)((picker.numberOfComponents - i - 2)));
  118. //sending three objects, so can't use performSelector:
  119. if ([target respondsToSelector:action])
  120. {
  121. void (*response)(id, SEL, id, id,id) = (void (*)(id, SEL, id, id,id)) objc_msgSend;
  122. response(target, action, @(bigUnits), @(smallUnits), origin);
  123. }
  124. else
  125. NSAssert(NO, @"Invalid target/action ( %s / %s ) combination used for ActionSheetPicker", object_getClassName(target), sel_getName(action));
  126. }
  127. #pragma mark -
  128. #pragma mark UIPickerViewDataSource
  129. - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
  130. return self.bigUnitDigits + self.smallUnitDigits + 2;
  131. }
  132. - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
  133. //for labels
  134. if (component == self.bigUnitDigits || component == self.bigUnitDigits + self.smallUnitDigits + 1)
  135. return 1;
  136. if (component + 1 <= self.bigUnitDigits) {
  137. if (component == 0)
  138. return self.bigUnitMax / (int)pow((double)10, (double)(self.bigUnitDigits - 1)) + 1;
  139. return 10;
  140. }
  141. if (component == self.bigUnitDigits + 1)
  142. return self.smallUnitMax / (int)pow((double)10, (double)(self.smallUnitDigits - 1)) + 1;
  143. return 10;
  144. }
  145. - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
  146. CGFloat totalWidth = pickerView.frame.size.width - 30;
  147. CGFloat otherSize = (totalWidth )/(self.bigUnitDigits + self.smallUnitDigits + 2);
  148. UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, otherSize, 30)];
  149. label.textAlignment = NSTextAlignmentCenter;
  150. label.font = [UIFont boldSystemFontOfSize:20];
  151. if ( component == self.bigUnitDigits )
  152. {
  153. label.text = self.bigUnitString;
  154. return label;
  155. }
  156. else if ( component == self.bigUnitDigits + self.smallUnitDigits + 1 )
  157. {
  158. label.text = self.smallUnitString;
  159. return label;
  160. }
  161. label.font = [UIFont systemFontOfSize:20];
  162. label.text = [NSString stringWithFormat:@"%li", (long)row];
  163. return label;
  164. }
  165. - (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component {
  166. CGFloat totalWidth = pickerView.frame.size.width - 30;
  167. CGFloat otherSize = (totalWidth )/(self.bigUnitDigits + self.smallUnitDigits + 2);
  168. return otherSize;
  169. }
  170. - (void)customButtonPressed:(id)sender {
  171. NSLog(@"Not implemented. If you get around to it, please contribute back to the project :)");
  172. }
  173. @end