JTNumberScrollAnimatedView.m 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. //
  2. // JTNumberScrollAnimatedView.m
  3. // JTNumberScrollAnimatedView
  4. //
  5. // Created by Jonathan Tribouharet
  6. //
  7. #import "JTNumberScrollAnimatedView.h"
  8. @interface JTNumberScrollAnimatedView(){
  9. NSMutableArray *numbersText;
  10. NSMutableArray *scrollLayers;
  11. NSMutableArray *scrollLabels;
  12. }
  13. @end
  14. @implementation JTNumberScrollAnimatedView
  15. - (instancetype)initWithFrame:(CGRect)frame
  16. {
  17. self = [super initWithFrame:frame];
  18. if(!self){
  19. return nil;
  20. }
  21. [self commonInit];
  22. return self;
  23. }
  24. - (id)initWithCoder:(NSCoder *)aDecoder
  25. {
  26. self = [super initWithCoder:aDecoder];
  27. if(!self){
  28. return nil;
  29. }
  30. [self commonInit];
  31. return self;
  32. }
  33. - (void)commonInit
  34. {
  35. self.duration = 3;
  36. self.durationOffset = 0.5;
  37. self.density = 5;
  38. self.isAscending = YES;
  39. [self setValue:[NSNumber numberWithInt:50]];
  40. self.font = [UIFont fontWithName:kPFSCFont size:[UIFont systemFontSize]];
  41. self.textColor = [UIColor blackColor];
  42. numbersText = [NSMutableArray new];
  43. scrollLayers = [NSMutableArray new];
  44. scrollLabels = [NSMutableArray new];
  45. }
  46. - (void)setValue:(NSNumber *)value
  47. {
  48. self->_value = value;
  49. NSString *textValue = [self.value stringValue];
  50. self.minLength = textValue.length+1;
  51. [self prepareAnimations];
  52. }
  53. - (void)startAnimation
  54. {
  55. [self prepareAnimations];
  56. [self createAnimations];
  57. }
  58. - (void)stopAnimation
  59. {
  60. for(CALayer *layer in scrollLayers){
  61. [layer removeAnimationForKey:@"JTNumberScrollAnimatedView"];
  62. }
  63. }
  64. - (void)prepareAnimations
  65. {
  66. for(CALayer *layer in scrollLayers){
  67. [layer removeFromSuperlayer];
  68. }
  69. [numbersText removeAllObjects];
  70. [scrollLayers removeAllObjects];
  71. [scrollLabels removeAllObjects];
  72. [self createNumbersText];
  73. [self createScrollLayers];
  74. }
  75. - (void)createNumbersText
  76. {
  77. NSString *textValue = [self.value stringValue];
  78. for(NSInteger i = 0; i < (NSInteger)self.minLength - (NSInteger)[textValue length]; ++i){
  79. [numbersText addObject:@""];
  80. }
  81. for(NSUInteger i = 0; i < [textValue length]; ++i){
  82. [numbersText addObject:[textValue substringWithRange:NSMakeRange(i, 1)]];
  83. }
  84. }
  85. - (void)createScrollLayers
  86. {
  87. CGFloat width = 25;
  88. CGFloat height = 35;
  89. for(NSUInteger i = 0; i < numbersText.count; ++i){
  90. CAScrollLayer *layer = [CAScrollLayer layer];
  91. if (i==0) {
  92. layer.frame = CGRectMake(roundf(-100 * width), 0, width, height);
  93. }else{
  94. layer.frame = CGRectMake(roundf(i * width), 0, width, height);
  95. }
  96. [scrollLayers addObject:layer];
  97. [self.layer addSublayer:layer];
  98. }
  99. for(NSUInteger i = 0; i < numbersText.count; ++i){
  100. CAScrollLayer *layer = scrollLayers[i];
  101. NSString *numberText = numbersText[i];
  102. [self createContentForLayer:layer withNumberText:numberText];
  103. }
  104. }
  105. - (void)createContentForLayer:(CAScrollLayer *)scrollLayer withNumberText:(NSString *)numberText
  106. {
  107. NSInteger number = [numberText integerValue];
  108. NSMutableArray *textForScroll = [NSMutableArray new];
  109. for(NSUInteger i = 0; i < self.density + 1; ++i){
  110. [textForScroll addObject:[NSString stringWithFormat:@"%ld", (number + i) % 10]];
  111. }
  112. [textForScroll addObject:numberText];
  113. if(!self.isAscending){
  114. textForScroll = [[[textForScroll reverseObjectEnumerator] allObjects] mutableCopy];
  115. }
  116. CGFloat height = 0;
  117. for(NSString *text in textForScroll){
  118. UIImageView * textLabel = [self createLabel:text];
  119. textLabel.frame = CGRectMake(0, height, CGRectGetWidth(scrollLayer.frame), CGRectGetHeight(scrollLayer.frame));
  120. [scrollLayer addSublayer:textLabel.layer];
  121. [scrollLabels addObject:textLabel];
  122. height = CGRectGetMaxY(textLabel.frame);
  123. }
  124. }
  125. - (UIImageView *)createLabel:(NSString *)text
  126. {
  127. UIImageView *view = [[UIImageView alloc] init];
  128. view.contentMode = UIViewContentModeScaleAspectFit;
  129. view.image = [UIImage imageNamed:[NSString stringWithFormat:@"num_anim_%@",text]];
  130. return view;
  131. }
  132. - (void)createAnimations
  133. {
  134. CFTimeInterval duration = self.duration - ([numbersText count] * self.durationOffset);
  135. CFTimeInterval offset = 0;
  136. [scrollLayers removeObjectAtIndex:0];
  137. for(int i = (int)scrollLayers.count-1; i>=0; i--){
  138. CALayer *scrollLayer = scrollLayers[i];
  139. CGFloat maxY = [[scrollLayer.sublayers lastObject] frame].origin.y;
  140. CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.y"];
  141. animation.duration = duration + offset;
  142. animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
  143. if(self.isAscending){
  144. animation.fromValue = [NSNumber numberWithFloat:-maxY];
  145. animation.toValue = @0;
  146. }
  147. else{
  148. animation.fromValue = @0;
  149. animation.toValue = [NSNumber numberWithFloat:-maxY];
  150. }
  151. [scrollLayer addAnimation:animation forKey:@"JTNumberScrollAnimatedView"];
  152. offset += self.durationOffset;
  153. }
  154. if (self.minLength < 5) {
  155. offset = offset + 2;
  156. }
  157. [self.delegate numberScrollAnimatedViewTime:offset];
  158. }
  159. @end