ActionSheetStringPicker.m 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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 "ActionSheetStringPicker.h"
  28. @interface ActionSheetStringPicker()
  29. @property (nonatomic,strong) NSArray *data;
  30. @property (nonatomic,assign) NSInteger selectedIndex;
  31. @end
  32. @implementation ActionSheetStringPicker
  33. + (instancetype)showPickerWithTitle:(NSString *)title rows:(NSArray *)strings initialSelection:(NSInteger)index doneBlock:(ActionStringDoneBlock)doneBlock cancelBlock:(ActionStringCancelBlock)cancelBlockOrNil origin:(id)origin {
  34. ActionSheetStringPicker * picker = [[ActionSheetStringPicker alloc] initWithTitle:title rows:strings initialSelection:index doneBlock:doneBlock cancelBlock:cancelBlockOrNil origin:origin];
  35. [picker showActionSheetPicker];
  36. return picker;
  37. }
  38. - (instancetype)initWithTitle:(NSString *)title rows:(NSArray *)strings initialSelection:(NSInteger)index doneBlock:(ActionStringDoneBlock)doneBlock cancelBlock:(ActionStringCancelBlock)cancelBlockOrNil origin:(id)origin {
  39. self = [self initWithTitle:title rows:strings initialSelection:index target:nil successAction:nil cancelAction:nil origin:origin];
  40. if (self) {
  41. self.onActionSheetDone = doneBlock;
  42. self.onActionSheetCancel = cancelBlockOrNil;
  43. }
  44. return self;
  45. }
  46. + (instancetype)showPickerWithTitle:(NSString *)title rows:(NSArray *)data initialSelection:(NSInteger)index target:(id)target successAction:(SEL)successAction cancelAction:(SEL)cancelActionOrNil origin:(id)origin {
  47. ActionSheetStringPicker *picker = [[ActionSheetStringPicker alloc] initWithTitle:title rows:data initialSelection:index target:target successAction:successAction cancelAction:cancelActionOrNil origin:origin];
  48. [picker showActionSheetPicker];
  49. return picker;
  50. }
  51. - (instancetype)initWithTitle:(NSString *)title rows:(NSArray *)data initialSelection:(NSInteger)index target:(id)target successAction:(SEL)successAction cancelAction:(SEL)cancelActionOrNil origin:(id)origin {
  52. self = [self initWithTarget:target successAction:successAction cancelAction:cancelActionOrNil origin:origin];
  53. if (self) {
  54. self.data = data;
  55. self.selectedIndex = index;
  56. self.title = title;
  57. }
  58. return self;
  59. }
  60. - (UIView *)configuredPickerView {
  61. if (!self.data)
  62. return nil;
  63. CGRect pickerFrame = CGRectMake(0, 40, self.viewSize.width, 216);
  64. UIPickerView *stringPicker = [[UIPickerView alloc] initWithFrame:pickerFrame];
  65. stringPicker.delegate = self;
  66. stringPicker.dataSource = self;
  67. [stringPicker selectRow:self.selectedIndex inComponent:0 animated:NO];
  68. if (self.data.count == 0) {
  69. stringPicker.showsSelectionIndicator = NO;
  70. stringPicker.userInteractionEnabled = NO;
  71. } else {
  72. stringPicker.showsSelectionIndicator = YES;
  73. stringPicker.userInteractionEnabled = YES;
  74. }
  75. //need to keep a reference to the picker so we can clear the DataSource / Delegate when dismissing
  76. self.pickerView = stringPicker;
  77. return stringPicker;
  78. }
  79. - (void)notifyTarget:(id)target didSucceedWithAction:(SEL)successAction origin:(id)origin {
  80. if (self.onActionSheetDone) {
  81. id selectedObject = (self.data.count > 0) ? (self.data)[(NSUInteger) self.selectedIndex] : nil;
  82. _onActionSheetDone(self, self.selectedIndex, selectedObject);
  83. return;
  84. }
  85. else if (target && [target respondsToSelector:successAction]) {
  86. #pragma clang diagnostic push
  87. #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
  88. [target performSelector:successAction withObject:@(self.selectedIndex) withObject:origin];
  89. #pragma clang diagnostic pop
  90. return;
  91. }
  92. NSLog(@"Invalid target/action ( %s / %s ) combination used for ActionSheetPicker and done block is nil.", object_getClassName(target), sel_getName(successAction));
  93. }
  94. - (void)notifyTarget:(id)target didCancelWithAction:(SEL)cancelAction origin:(id)origin {
  95. if (self.onActionSheetCancel) {
  96. _onActionSheetCancel(self);
  97. return;
  98. }
  99. else if (target && cancelAction && [target respondsToSelector:cancelAction]) {
  100. #pragma clang diagnostic push
  101. #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
  102. [target performSelector:cancelAction withObject:origin];
  103. #pragma clang diagnostic pop
  104. }
  105. }
  106. #pragma mark - UIPickerViewDelegate / DataSource
  107. - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
  108. self.selectedIndex = row;
  109. }
  110. - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
  111. return 1;
  112. }
  113. - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
  114. return self.data.count;
  115. }
  116. - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
  117. id obj = (self.data)[(NSUInteger) row];
  118. // return the object if it is already a NSString,
  119. // otherwise, return the description, just like the toString() method in Java
  120. // else, return nil to prevent exception
  121. if ([obj isKindOfClass:[NSString class]])
  122. return obj;
  123. if ([obj respondsToSelector:@selector(description)])
  124. return [obj performSelector:@selector(description)];
  125. return nil;
  126. }
  127. - (NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component {
  128. id obj = (self.data)[(NSUInteger) row];
  129. // return the object if it is already a NSString,
  130. // otherwise, return the description, just like the toString() method in Java
  131. // else, return nil to prevent exception
  132. if ([obj isKindOfClass:[NSString class]])
  133. return [[NSAttributedString alloc] initWithString:obj attributes:self.pickerTextAttributes];
  134. if ([obj respondsToSelector:@selector(description)])
  135. return [[NSAttributedString alloc] initWithString:[obj performSelector:@selector(description)] attributes:self.pickerTextAttributes];
  136. return nil;
  137. }
  138. - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
  139. UILabel *pickerLabel = (UILabel *)view;
  140. if (pickerLabel == nil) {
  141. pickerLabel = [[UILabel alloc] init];
  142. }
  143. id obj = (self.data)[(NSUInteger) row];
  144. NSAttributedString *attributeTitle = nil;
  145. // use the object if it is already a NSString,
  146. // otherwise, use the description, just like the toString() method in Java
  147. // else, use String with no text to ensure this delegate do not return a nil value.
  148. if ([obj isKindOfClass:[NSString class]])
  149. attributeTitle = [[NSAttributedString alloc] initWithString:obj attributes:self.pickerTextAttributes];
  150. if ([obj respondsToSelector:@selector(description)])
  151. attributeTitle = [[NSAttributedString alloc] initWithString:[obj performSelector:@selector(description)] attributes:self.pickerTextAttributes];
  152. if (attributeTitle == nil) {
  153. attributeTitle = [[NSAttributedString alloc] initWithString:@"" attributes:self.pickerTextAttributes];
  154. }
  155. pickerLabel.attributedText = attributeTitle;
  156. return pickerLabel;
  157. }
  158. - (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component {
  159. return pickerView.frame.size.width - 30;
  160. }
  161. @end