天天看点

iOS动画之大雪纷飞

1.结果展示

美丽的雪花,勾起了多少骚年美好的回忆。^_^

iOS动画之大雪纷飞

2.制作思路

其实创作这样一个大学纷飞的场景是十分简单的,简单到你看了教程之后想不会都不行。OK,下面国际惯例,讲解一下思路吧。

1.创建一个数组用来保存大量的雪花

_imagesArray = [[NSMutableArray alloc] init];
    for (int i = ; i < ; ++ i) {
        UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"snow"]];
        float x = IMAGE_WIDTH;
        imageView.frame = CGRectMake(IMAGE_X, -, x, x);
        imageView.alpha = IMAGE_ALPHA;
        [self.view addSubview:imageView];
        [_imagesArray addObject:imageView];
    }
           

2.使用时钟(CADisplayLink)来控制下雪,为什么不使用NSTimer呢。其实是可以的,只是(CADisplayLink)刷帧更快一些。

//创建时钟,并且添加到主循环中
    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(makeSnow)];
    [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
           

3.下雪,就是把数组当做队列来使用。

  1. 每次从数组头部取出一个雪花并且删除其在数组中的占位。
  2. 让雪花飘落,通过UIView动画完成frame,transform等改变。
  3. 当动画完成之后,将取出的雪花再次放进数组的尾部
- (void)makeSnow
{
    if (_imagesArray.count > ) {
        UIImageView *imageView = _imagesArray[];
        [_imagesArray removeObjectAtIndex:];
        [self snowFall:imageView];
    }
}

- (void)snowFall:(UIImageView *)imageView
{
    [UIView animateWithDuration: animations:^{
        imageView.frame = CGRectMake(imageView.frame.origin.x, Main_Screen_Height, imageView.frame.size.width, imageView.frame.size.height);
        imageView.transform = CGAffineTransformMakeScale(, );
        imageView.transform = CGAffineTransformRotate(imageView.transform, M_PI);
    } completion:^(BOOL finished) {
        float x = IMAGE_WIDTH;
        imageView.frame = CGRectMake(IMAGE_X, -, x, x);
        [_imagesArray addObject:imageView];
    }];
}
           

3.有代码有真相

#define IMAGE_X                arc4random()%(int)Main_Screen_Width
#define IMAGE_ALPHA            ((float)(arc4random()%10))/10
#define IMAGE_WIDTH            arc4random()%20 + 10
#define PLUS_HEIGHT            Main_Screen_Height/25

#define Main_Screen_Height      [[UIScreen mainScreen] bounds].size.height
#define Main_Screen_Width       [[UIScreen mainScreen] bounds].size.width

#import "ViewController.h"

@interface ViewController ()
@property (nonatomic ,strong) NSMutableArray *imagesArray;
@property (nonatomic , strong) UIImageView *imageView;
@end

@implementation ViewController

- (void)loadView
{
    UIImageView *imageView = [[UIImageView alloc]initWithFrame:[UIScreen mainScreen].bounds];
    imageView.image = [UIImage imageNamed:@"backgound.jpg"];
    imageView.contentMode  = UIViewContentModeScaleAspectFill;
    self.view = imageView;

}

- (void)viewDidLoad
{
    [super viewDidLoad];

    _imagesArray = [[NSMutableArray alloc] init];
    for (int i = ; i < ; ++ i) {
        UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"snow"]];
        float x = IMAGE_WIDTH;
        imageView.frame = CGRectMake(IMAGE_X, -, x, x);
        imageView.alpha = IMAGE_ALPHA;
        [self.view addSubview:imageView];
        [_imagesArray addObject:imageView];
    }

    //创建时钟,并且添加到主循环中
    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(makeSnow)];
    [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}


- (void)makeSnow
{
    if (_imagesArray.count > ) {
        UIImageView *imageView = _imagesArray[];
        [_imagesArray removeObjectAtIndex:];
        [self snowFall:imageView];
    }
}

- (void)snowFall:(UIImageView *)imageView
{
    [UIView animateWithDuration: animations:^{
        imageView.frame = CGRectMake(imageView.frame.origin.x, Main_Screen_Height, imageView.frame.size.width, imageView.frame.size.height);
        imageView.transform = CGAffineTransformMakeScale(, );
        imageView.transform = CGAffineTransformRotate(imageView.transform, M_PI);
    } completion:^(BOOL finished) {
        float x = IMAGE_WIDTH;
        imageView.frame = CGRectMake(IMAGE_X, -, x, x);
        [_imagesArray addObject:imageView];
    }];
}
           

4.Demo也不能少

https://github.com/Esdeath/snow/tree/master/SnowFlyTwo