DistancePickerView.m 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. //
  2. // DistancePickerView.m
  3. //
  4. // Created by Evan on 12/27/10.
  5. // Copyright 2010 NCPTT. All rights reserved.
  6. //
  7. // Adapted from LabeledPickerView by Kåre Morstøl (NotTooBad Software).
  8. // This file only Copyright (c) 2009 Kåre Morstøl (NotTooBad Software).
  9. // This file only under the Eclipse public license v1.0
  10. // http://www.eclipse.org/legal/epl-v10.html
  11. #import "DistancePickerView.h"
  12. @implementation DistancePickerView
  13. - (instancetype)initWithFrame:(CGRect)frame
  14. {
  15. self = [super initWithFrame:frame];
  16. if ( self )
  17. {
  18. labels = [[NSMutableDictionary alloc] initWithCapacity:2];
  19. }
  20. return self;
  21. }
  22. - (void)addLabel:(NSString *)labeltext forComponent:(NSUInteger)component forLongestString:(NSString *)longestString
  23. {
  24. labels[@(component)] = labeltext;
  25. NSString *keyName = [NSString stringWithFormat:@"%@_%ld", @"longestString", (unsigned long)component];
  26. if ( !longestString )
  27. {
  28. longestString = labeltext;
  29. }
  30. labels[keyName] = longestString;
  31. }
  32. - (void)updateLabel:(NSString *)labeltext forComponent:(NSUInteger)component
  33. {
  34. UILabel *theLabel = (UILabel *) [self viewWithTag:component + 1];
  35. // Update label if it doesn’t match current label
  36. if ( ![theLabel.text isEqualToString:labeltext] )
  37. {
  38. NSString *keyName = [NSString stringWithFormat:@"%@_%ld", @"longestString", (unsigned long)component];
  39. NSString *longestString = labels[keyName];
  40. // Update label array with our new string value
  41. [self addLabel:labeltext forComponent:component forLongestString:longestString];
  42. // change label during fade out/in
  43. [UIView beginAnimations:nil context:NULL];
  44. [UIView setAnimationDuration:0.75];
  45. [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
  46. theLabel.alpha = 0.00;
  47. theLabel.text = labeltext;
  48. theLabel.alpha = 1.00;
  49. [UIView commitAnimations];
  50. }
  51. }
  52. /**
  53. Adds the labels to the view, below the selection indicator glass.
  54. The labels are aligned to the right side of the wheel.
  55. The delegate is responsible for providing enough width for both the value and the label.
  56. */
  57. - (void)didMoveToWindow
  58. {
  59. // exit if view is removed from the window or there are no labels.
  60. if ( !self.window || [labels count] == 0 )
  61. return;
  62. UIFont *labelfont = [UIFont boldSystemFontOfSize:20];
  63. // find the width of all the wheels combined
  64. CGFloat widthofwheels = 0;
  65. for (int i = 0; i < self.numberOfComponents; i++)
  66. {
  67. widthofwheels += [self rowSizeForComponent:i].width;
  68. }
  69. // find the left side of the first wheel.
  70. // seems like a misnomer, but that will soon be corrected.
  71. CGFloat rightsideofwheel = (self.frame.size.width - widthofwheels) / 2;
  72. // cycle through all wheels
  73. for (int component = 0; component < self.numberOfComponents; component++)
  74. {
  75. // find the right side of the wheel
  76. rightsideofwheel += [self rowSizeForComponent:component].width;
  77. // get the text for the label.
  78. // move on to the next if there is no label for this wheel.
  79. NSString *text = labels[@(component)];
  80. if ( text )
  81. {
  82. // set up the frame for the label using our longestString length
  83. NSString *keyName = [NSString stringWithFormat:@"%@_%@", @"longestString",
  84. @(component)];
  85. NSString *longestString = labels[keyName];
  86. CGRect frame;
  87. if ( NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1)
  88. {
  89. #pragma clang diagnostic push
  90. #pragma ide diagnostic ignored "UnavailableInDeploymentTarget"
  91. frame.size = [longestString sizeWithAttributes:
  92. @{NSFontAttributeName :
  93. labelfont}];
  94. #pragma clang diagnostic pop
  95. }
  96. else
  97. {
  98. #pragma clang diagnostic push
  99. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  100. frame.size = [longestString sizeWithFont:labelfont];
  101. #pragma clang diagnostic pop
  102. }
  103. // center it vertically
  104. frame.origin.y = (CGFloat) ((self.frame.size.height / 2.f) - (frame.size.height / 2.f) - 0.5f);
  105. // align it to the right side of the wheel, with a margin.
  106. // use a smaller margin for the rightmost wheel.
  107. frame.origin.x = rightsideofwheel - frame.size.width - (component == self.numberOfComponents - 1 ? 5 : 7);
  108. // set up the label. If label already exists, just get a reference to it
  109. BOOL addlabelView = NO;
  110. UILabel *label = (UILabel *) [self viewWithTag:component + 1];
  111. if ( !label )
  112. {
  113. label = [[UILabel alloc] initWithFrame:frame];
  114. addlabelView = YES;
  115. }
  116. label.text = text;
  117. label.font = labelfont;
  118. label.backgroundColor = [UIColor clearColor];
  119. label.shadowColor = [UIColor whiteColor];
  120. label.shadowOffset = CGSizeMake(0, 1);
  121. // Tag cannot be 0 so just increment component number to esnure we get a positive
  122. // NB update/remove Label methods are aware of this incrementation!
  123. label.tag = component + 1;
  124. if ( addlabelView )
  125. {
  126. /*
  127. and now for the tricky bit: adding the label to the view.
  128. kind of a hack to be honest, might stop working if Apple decides to
  129. change the inner workings of the UIPickerView.
  130. */
  131. if ( self.showsSelectionIndicator )
  132. {
  133. // if this is the last wheel, add label as the third view from the top
  134. if ( component == self.numberOfComponents - 1 ) if ( NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1)
  135. {
  136. UIView *o = [self.subviews[0] subviews][[[self.subviews[0] subviews] count] - 1];
  137. UIView *subview = [o subviews][2];
  138. UIView *view = [(subview.subviews)[0] subviews][1];
  139. [self insertSubview:label aboveSubview:view];
  140. }
  141. else
  142. {
  143. [self insertSubview:label atIndex:[self.subviews count] - 3];
  144. }
  145. // otherwise add label as the 5th, 10th, 15th etc view from the top
  146. else
  147. {
  148. if ( NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1)
  149. {
  150. [self insertSubview:label
  151. aboveSubview:[self.subviews[0] subviews][(NSUInteger) component]];
  152. }
  153. else
  154. {
  155. [self insertSubview:label aboveSubview:(self.subviews)[(NSUInteger) (5 * (component + 1))]];
  156. }
  157. }
  158. } else
  159. // there is no selection indicator, so just add it to the top
  160. [self addSubview:label];
  161. }
  162. if ( [self.delegate respondsToSelector:@selector(pickerView:didSelectRow:inComponent:)] )
  163. [self.delegate pickerView:self didSelectRow:[self selectedRowInComponent:component]
  164. inComponent:component];
  165. }
  166. }
  167. }
  168. @end