iOS snow animation
// // CTSnowAnimationView.h // CTMyCtrip // // Created by alex on 16/1/4. // Copyright © 2016年 ctrip. All rights reserved. // #import <UIKit/UIKit.h> @interface CTSnowAnimationView : UIView -(id)initWithFrame:(CGRect)frame; -(void)startSnowWithFlakesNumber:(int)num duration:(float)duration; -(void)stopSnowAnimation; -(void)removeSnowAnimation; @end
// // CTSnowAnimationView.m // CTMyCtrip // // Created by alex on 16/1/4. // Copyright © 2016年 ctrip. All rights reserved. // #import "CTSnowAnimationView.h" #define REPEATSNOW @"geneRepeatSnow" @interface CTSnowAnimationView() @property (strong, nonatomic) NSMutableArray<UIImageView*> *snowFlakes; @end @implementation CTSnowAnimationView -(id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { return self; } return [[CTSnowAnimationView alloc] init]; } -(void)removeSnowAnimation{ for (UIView *flake in self.snowFlakes) { [flake removeFromSuperview]; } [[NSNotificationCenter defaultCenter] removeObserver:self name:REPEATSNOW object:nil]; self.snowFlakes = nil; } -(void)startSnowWithFlakesNumber:(int)num duration:(float)duration{ dispatch_async(dispatch_get_main_queue(), ^{ if ([self.snowFlakes count] != num) { if ([self.snowFlakes count] != 0) { for (UIView *subview in self.snowFlakes) { [subview removeFromSuperview]; } } self.snowFlakes = [NSMutableArray array]; for (int i = 0; i < num; i++) { UIImageView *tmpView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"myctrip_snowflake.png"]]; tmpView.frame = CGRectZero; tmpView.userInteractionEnabled = FALSE; [self addSubview:tmpView]; [self.snowFlakes addObject:tmpView]; } } [self showFlakes:YES]; [[NSNotificationCenter defaultCenter] removeObserver:self name:REPEATSNOW object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveRepeatNotification:) name:REPEATSNOW object:nil]; for (UIView *flake in self.snowFlakes) { [flake.layer removeAllAnimations]; } for (int i = 0; i < [self.snowFlakes count]; i++) { [self singleFlakeSnow:i withDuration:duration]; } }); } -(void)stopSnowAnimation{ for (UIView *flake in self.snowFlakes) { [flake.layer removeAllAnimations]; } [self showFlakes:false]; } - (float)randomFloatBetween:(float)min and:(float)max { float diff = max - min; return (((float) (arc4random() % ((unsigned)RAND_MAX + 1)) / RAND_MAX) * diff) + min; } -(void)showFlakes:(BOOL)need{ for (UIImageView *flake in self.snowFlakes) { flake.hidden = !need; } } -(void)singleFlakeSnow:(int)index withDuration:(float)duration{ UIView *flake = self.snowFlakes[index]; int size = [self randomFloatBetween:8.0 and:14.0]; CGRect flakeFrame = flake.frame; [flake.layer removeAllAnimations]; flake.layer.opacity = 0.1; flakeFrame.origin.x = arc4random_uniform(CTScreenWidth); flakeFrame.origin.y = -size; flakeFrame.size.width = size; flakeFrame.size.height = size; flake.frame = flakeFrame; float delay = arc4random_uniform(5.0); [self layoutIfNeeded]; [UIView animateWithDuration:duration delay:delay options:UIViewAnimationOptionCurveEaseInOut animations:^{ flake.frame = CGRectMake(flakeFrame.origin.x + 40 - arc4random_uniform(80), self.bounds.size.height, size, size); flake.layer.opacity = 1.0; [self layoutIfNeeded]; } completion:^(BOOL finished) { if (finished) { [[NSNotificationCenter defaultCenter] postNotificationName:REPEATSNOW object:nil userInfo:@{@"index":[NSNumber numberWithInt:index], @"duration":[NSNumber numberWithFloat:duration] }]; } }]; } -(void)receiveRepeatNotification:(NSNotification *)notification{ if ([[notification name] isEqualToString:REPEATSNOW]) { int index = [((NSNumber*)[notification.userInfo objectForKey:@"index"]) intValue]; float duration = [((NSNumber*)[notification.userInfo objectForKey:@"duration"]) floatValue]; [self singleFlakeSnow:index withDuration:duration]; } } @end
Using AutoLayout:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 - (float)randomFloatBetween:(float)min and:(float)max { 2 float diff = max - min; 3 return (((float) (arc4random() % ((unsigned)RAND_MAX + 1)) / RAND_MAX) * diff) + min; 4 } 5 6 -(void)showFlakes:(BOOL)need{ 7 for (UIImageView *flake in self.snowFlakes) { 8 flake.hidden = !need; 9 } 10 } 11 12 -(void)singleFlakeSnow:(int)index{ 13 UIView *flake = self.snowFlakes[index]; 14 NSLayoutConstraint *x = self.flakesHorizonalPosition[index]; 15 NSLayoutConstraint *y = self.flakesVerticalPosition[index]; 16 int size = [self randomFloatBetween:8.0 and:14.0]; 17 ((NSLayoutConstraint*)self.flakesWidth[index]).constant = size; 18 ((NSLayoutConstraint*)self.flakesHeight[index]).constant = size; 19 [flake.layer removeAllAnimations]; 20 flake.layer.opacity = 0.1; 21 x.constant = arc4random_uniform(CTScreenWidth); 22 y.constant = -size; 23 float delay = arc4random_uniform(5.0); 24 [self layoutIfNeeded]; 25 [UIView animateWithDuration:7.0 delay:delay options:UIViewAnimationOptionCurveEaseInOut animations:^{ 26 x.constant = x.constant + 40 - arc4random_uniform(80); 27 y.constant = self.bounds.size.height; 28 flake.layer.opacity = 1.0; 29 [self layoutIfNeeded]; 30 } completion:^(BOOL finished) { 31 if (finished) { 32 [[NSNotificationCenter defaultCenter] postNotificationName:REPEATSNOW object:nil userInfo:@{@"index":[NSNumber numberWithInt:index]}]; 33 } 34 }]; 35 } 36 37 -(void)snowAnimation:(BOOL)need{ 38 if (need ) { 39 dispatch_async(dispatch_get_main_queue(), ^{ 40 [self showFlakes:YES]; 41 self.snowGround.hidden = FALSE; 42 self.snowBackground.hidden = FALSE; 43 [[NSNotificationCenter defaultCenter] removeObserver:self name:REPEATSNOW object:nil]; 44 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveRepeatNotification:) name:REPEATSNOW object:nil]; 45 for (UIView *flake in self.snowFlakes) { 46 [flake.layer removeAllAnimations]; 47 } 48 for (int i = 0; i < [self.snowFlakes count]; i++) { 49 [self singleFlakeSnow:i]; 50 } 51 }); 52 } 53 else{ 54 dispatch_async(dispatch_get_main_queue(), ^{ 55 [[NSNotificationCenter defaultCenter] removeObserver:self name:REPEATSNOW object:nil]; 56 for (UIView *flake in self.snowFlakes) { 57 [flake.layer removeAllAnimations]; 58 } 59 [self showFlakes:NO]; 60 }); 61 } 62 } 63 64 -(void)receiveRepeatNotification:(NSNotification *)notification{ 65 if ([[notification name] isEqualToString:REPEATSNOW]) { 66 int index = [((NSNumber*)[notification.userInfo objectForKey:@"index"]) intValue]; 67 [self singleFlakeSnow:index]; 68 } 69 }