// // JTNumberScrollAnimatedView.m // JTNumberScrollAnimatedView // // Created by Jonathan Tribouharet // #import "JTNumberScrollAnimatedView.h" @interface JTNumberScrollAnimatedView(){ NSMutableArray *numbersText; NSMutableArray *scrollLayers; NSMutableArray *scrollLabels; } @end @implementation JTNumberScrollAnimatedView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if(!self){ return nil; } [self commonInit]; return self; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if(!self){ return nil; } [self commonInit]; return self; } - (void)commonInit { self.duration = 3; self.durationOffset = 0.5; self.density = 5; self.isAscending = YES; [self setValue:[NSNumber numberWithInt:50]]; self.font = [UIFont fontWithName:kPFSCFont size:[UIFont systemFontSize]]; self.textColor = [UIColor blackColor]; numbersText = [NSMutableArray new]; scrollLayers = [NSMutableArray new]; scrollLabels = [NSMutableArray new]; } - (void)setValue:(NSNumber *)value { self->_value = value; NSString *textValue = [self.value stringValue]; self.minLength = textValue.length+1; [self prepareAnimations]; } - (void)startAnimation { [self prepareAnimations]; [self createAnimations]; } - (void)stopAnimation { for(CALayer *layer in scrollLayers){ [layer removeAnimationForKey:@"JTNumberScrollAnimatedView"]; } } - (void)prepareAnimations { for(CALayer *layer in scrollLayers){ [layer removeFromSuperlayer]; } [numbersText removeAllObjects]; [scrollLayers removeAllObjects]; [scrollLabels removeAllObjects]; [self createNumbersText]; [self createScrollLayers]; } - (void)createNumbersText { NSString *textValue = [self.value stringValue]; for(NSInteger i = 0; i < (NSInteger)self.minLength - (NSInteger)[textValue length]; ++i){ [numbersText addObject:@""]; } for(NSUInteger i = 0; i < [textValue length]; ++i){ [numbersText addObject:[textValue substringWithRange:NSMakeRange(i, 1)]]; } } - (void)createScrollLayers { CGFloat width = 25; CGFloat height = 35; for(NSUInteger i = 0; i < numbersText.count; ++i){ CAScrollLayer *layer = [CAScrollLayer layer]; if (i==0) { layer.frame = CGRectMake(roundf(-100 * width), 0, width, height); }else{ layer.frame = CGRectMake(roundf(i * width), 0, width, height); } [scrollLayers addObject:layer]; [self.layer addSublayer:layer]; } for(NSUInteger i = 0; i < numbersText.count; ++i){ CAScrollLayer *layer = scrollLayers[i]; NSString *numberText = numbersText[i]; [self createContentForLayer:layer withNumberText:numberText]; } } - (void)createContentForLayer:(CAScrollLayer *)scrollLayer withNumberText:(NSString *)numberText { NSInteger number = [numberText integerValue]; NSMutableArray *textForScroll = [NSMutableArray new]; for(NSUInteger i = 0; i < self.density + 1; ++i){ [textForScroll addObject:[NSString stringWithFormat:@"%ld", (number + i) % 10]]; } [textForScroll addObject:numberText]; if(!self.isAscending){ textForScroll = [[[textForScroll reverseObjectEnumerator] allObjects] mutableCopy]; } CGFloat height = 0; for(NSString *text in textForScroll){ UIImageView * textLabel = [self createLabel:text]; textLabel.frame = CGRectMake(0, height, CGRectGetWidth(scrollLayer.frame), CGRectGetHeight(scrollLayer.frame)); [scrollLayer addSublayer:textLabel.layer]; [scrollLabels addObject:textLabel]; height = CGRectGetMaxY(textLabel.frame); } } - (UIImageView *)createLabel:(NSString *)text { UIImageView *view = [[UIImageView alloc] init]; view.contentMode = UIViewContentModeScaleAspectFit; view.image = [UIImage imageNamed:[NSString stringWithFormat:@"num_anim_%@",text]]; return view; } - (void)createAnimations { CFTimeInterval duration = self.duration - ([numbersText count] * self.durationOffset); CFTimeInterval offset = 0; [scrollLayers removeObjectAtIndex:0]; for(int i = (int)scrollLayers.count-1; i>=0; i--){ CALayer *scrollLayer = scrollLayers[i]; CGFloat maxY = [[scrollLayer.sublayers lastObject] frame].origin.y; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.y"]; animation.duration = duration + offset; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; if(self.isAscending){ animation.fromValue = [NSNumber numberWithFloat:-maxY]; animation.toValue = @0; } else{ animation.fromValue = @0; animation.toValue = [NSNumber numberWithFloat:-maxY]; } [scrollLayer addAnimation:animation forKey:@"JTNumberScrollAnimatedView"]; offset += self.durationOffset; } if (self.minLength < 5) { offset = offset + 2; } [self.delegate numberScrollAnimatedViewTime:offset]; } @end