// // RCAnimatedImagesView.m // RCloudMessage // // Created by 杜立召 on 15/3/18. // Copyright (c) 2015年 RongCloud. All rights reserved. // #import "RCAnimatedImagesView.h" #define noImageDisplayingIndex -1 #define imageSwappingAnimationDuration 2.0f #define imageViewsBorderOffset 150 @interface RCAnimatedImagesView() { BOOL animating; NSUInteger totalImages; NSUInteger currentlyDisplayingImageViewIndex; NSInteger currentlyDisplayingImageIndex; } @property (nonatomic, retain) NSArray *imageViews; @property (nonatomic, retain) NSTimer *imageSwappingTimer; - (void)_init; + (NSUInteger)randomIntBetweenNumber:(NSUInteger)minNumber andNumber:(NSUInteger)maxNumber; @end @implementation RCAnimatedImagesView @synthesize imageViews = _imageViews; @synthesize imageSwappingTimer = _imageSwappingTimer; @synthesize delegate = _delegate, timePerImage = _timePerImage; - (id)initWithCoder:(NSCoder *)aDecoder { if ((self = [super initWithCoder:aDecoder])) { [self _init]; } return self; } - (id)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { [self _init]; } return self; } - (void)_init { NSMutableArray *imageViews = [NSMutableArray array]; for (int i = 0; i < 2; i++) { UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(-imageViewsBorderOffset*3.3, -imageViewsBorderOffset, self.bounds.size.width + (imageViewsBorderOffset * 2), self.bounds.size.height + (imageViewsBorderOffset * 2))]; imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; imageView.contentMode = UIViewContentModeScaleAspectFill; imageView.clipsToBounds = NO; [self addSubview:imageView]; [imageViews addObject:imageView]; } self.imageViews = [imageViews copy]; currentlyDisplayingImageIndex = noImageDisplayingIndex; } - (void)startAnimating { if (!animating) { animating = YES; [self.imageSwappingTimer fire]; } } - (void)bringNextImage { UIImageView *imageViewToHide = [self.imageViews objectAtIndex:currentlyDisplayingImageViewIndex]; currentlyDisplayingImageViewIndex = currentlyDisplayingImageViewIndex == 0 ? 1 : 0; UIImageView *imageViewToShow = [self.imageViews objectAtIndex:currentlyDisplayingImageViewIndex]; NSUInteger nextImageToShowIndex = currentlyDisplayingImageIndex; do { nextImageToShowIndex = [[self class] randomIntBetweenNumber:0 andNumber:totalImages-1]; } while (nextImageToShowIndex == currentlyDisplayingImageIndex); currentlyDisplayingImageIndex = nextImageToShowIndex; imageViewToShow.image = [self.delegate animatedImagesView:self imageAtIndex:nextImageToShowIndex]; static const CGFloat kMovementAndTransitionTimeOffset = 0.1; [UIView animateWithDuration:self.timePerImage + imageSwappingAnimationDuration + kMovementAndTransitionTimeOffset delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationCurveLinear animations:^{ NSInteger randomTranslationValueX = imageViewsBorderOffset*3.5-[[self class] randomIntBetweenNumber:0 andNumber:imageViewsBorderOffset]; NSInteger randomTranslationValueY = 0; CGAffineTransform translationTransform = CGAffineTransformMakeTranslation(randomTranslationValueX, randomTranslationValueY); CGFloat randomScaleTransformValue = [[self class] randomIntBetweenNumber:115 andNumber:120]/100; CGAffineTransform scaleTransform = CGAffineTransformMakeScale(randomScaleTransformValue, randomScaleTransformValue); imageViewToShow.transform = CGAffineTransformConcat(scaleTransform, translationTransform); } completion:NULL]; [UIView animateWithDuration:imageSwappingAnimationDuration delay:kMovementAndTransitionTimeOffset options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationCurveLinear animations:^{ imageViewToShow.alpha = 1.0; imageViewToHide.alpha = 0.0; } completion:^(BOOL finished) { if (finished) { imageViewToHide.transform = CGAffineTransformIdentity; } }]; } - (void)reloadData { totalImages = [self.delegate animatedImagesNumberOfImages:self]; [self.imageSwappingTimer fire]; } - (void)stopAnimating { if (animating) { [_imageSwappingTimer invalidate]; _imageSwappingTimer = nil; [UIView animateWithDuration:imageSwappingAnimationDuration delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ for (UIImageView *imageView in self.imageViews) { imageView.alpha = 1; } } completion:^(BOOL finished) { currentlyDisplayingImageIndex = noImageDisplayingIndex; animating = NO; }]; } } - (NSTimeInterval)timePerImage { if (_timePerImage == 0) { return kJSAnimatedImagesViewDefaultTimePerImage; } return _timePerImage; } - (void)setDelegate:(id)delegate { if (delegate != _delegate) { _delegate = delegate; totalImages = [_delegate animatedImagesNumberOfImages:self]; } } - (NSTimer *)imageSwappingTimer { if (!_imageSwappingTimer) { _imageSwappingTimer = [NSTimer scheduledTimerWithTimeInterval:self.timePerImage target:self selector:@selector(bringNextImage) userInfo:nil repeats:YES]; } return _imageSwappingTimer; } + (NSUInteger)randomIntBetweenNumber:(NSUInteger)minNumber andNumber:(NSUInteger)maxNumber { if (minNumber > maxNumber) { return [self randomIntBetweenNumber:maxNumber andNumber:minNumber]; } NSUInteger i = (arc4random() % (maxNumber - minNumber + 1)) + minNumber; return i; } #pragma mark - Memory Management - (void)dealloc { [_imageSwappingTimer invalidate]; } @end