156 UIImageView 和 CADisplayLink 实现 Tom 汤姆猫动画效果的区别(扩展知识:分组(黄色文件夹)和文件夹引用(蓝色文件夹)区别)
(1)UIImageView 的动画操作,来自定义循环播放动画(不建议使用,内存消耗大)
(2)CADisplayLink 是一个计时器,但是同 NSTimer 不同的是,CADisplayLink 的刷新周期同屏幕完全一致。
例如在 iOS 中屏幕刷新周期是60次/秒,CADisplayLink 刷新周期同屏幕刷新一致也是60次/秒,这样一来使用它完成的逐帧动画(又称为“时钟动画”)完全感觉不到动画的停滞情况。
关键操作:
效果如下:
ViewController.h
1 #import <UIKit/UIKit.h> 2 3 @interface ViewController : UIViewController 4 @property (strong, nonatomic) UIImageView *imgVAnimation; 5 @property (strong, nonatomic) CADisplayLink *displayLink; 6 7 @end
ViewController.m
1 #import "ViewController.h" 2 3 @interface ViewController () 4 - (void)layoutUI; 5 - (void)changeImage; 6 - (void)layoutUINoSuggest; 7 - (NSArray *)imagesFromGroups; 8 - (NSArray *)imagesFromFolderReferences; 9 @end 10 11 @implementation ViewController 12 #define kImgCount 29 13 14 - (void)viewDidLoad { 15 [super viewDidLoad]; 16 17 //[self layoutUINoSuggest]; 18 19 [self layoutUI]; 20 } 21 22 - (void)viewWillAppear:(BOOL)animated { 23 [super viewWillAppear:animated]; 24 25 //开始动画;对应使用[self layoutUINoSuggest]的情况 26 //[_imgVAnimation startAnimating]; 27 28 //实例化时钟对象 29 _displayLink=[CADisplayLink displayLinkWithTarget:self selector:@selector(changeImage)]; 30 //添加时钟对象实例到主运行循环 31 [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 32 } 33 34 - (void)viewWillDisappear:(BOOL)animated { 35 [super viewWillDisappear:animated]; 36 37 //停止动画;对应使用[self layoutUINoSuggest]的情况 38 //[_imgVAnimation stopAnimating]; 39 40 //从主运行循环移除时钟对象实例 41 [_displayLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 42 } 43 44 - (void)didReceiveMemoryWarning { 45 [super didReceiveMemoryWarning]; 46 // Dispose of any resources that can be recreated. 47 } 48 49 #pragma mark - 推荐使用的方式 50 /** 51 * 使用CADisplayLink,来自定义循环播放动画(推荐使用,内存消耗小) 52 * CADisplayLink是一个计时器,但是同NSTimer不同的是,CADisplayLink的刷新周期同屏幕完全一致。例如在iOS中屏幕刷新周期是60次/秒,CADisplayLink刷新周期同屏幕刷新一致也是60次/秒,这样一来使用它完成的逐帧动画(又称为“时钟动画”)完全感觉不到动画的停滞情况 53 */ 54 - (void)layoutUI { 55 _imgVAnimation = [[UIImageView alloc] initWithFrame:self.view.bounds]; 56 [self.view addSubview:_imgVAnimation]; 57 } 58 59 - (void)changeImage { 60 //定义一个变量记录执行次数 61 static NSUInteger s=0; 62 static NSUInteger indexOfImg = 0; 63 //每秒执行12次if内的语句;分别当s=5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60... 64 s++; 65 if (s % 5 == 0) { 66 UIImage *image=[self imagesFromGroups][indexOfImg]; 67 _imgVAnimation.layer.contents=(id)image.CGImage; //更新图片 68 69 indexOfImg++; 70 if (indexOfImg == kImgCount) { 71 indexOfImg = 0; 72 } 73 } 74 } 75 76 #pragma mark - 不建议使用的方式 77 /** 78 * 使用图片视图的动画操作,来自定义循环播放动画(不建议使用,内存消耗大) 79 */ 80 - (void)layoutUINoSuggest { 81 _imgVAnimation = [[UIImageView alloc] initWithFrame:self.view.bounds]; 82 _imgVAnimation.animationImages = [self imagesFromGroups]; //引用图片数组,导致一次性加载图片数组,内存消耗大 83 //设置动画持续时间(图片播放周期时间,而不是播放一张图片的时间);单位为秒;默认值为每秒30帧(每秒播放30张图片) 84 _imgVAnimation.animationDuration = 3; 85 //设置动画播放重复次数;默认值为0,表示无限循环 86 _imgVAnimation.animationRepeatCount = 0; 87 [self.view addSubview:_imgVAnimation]; 88 } 89 90 #pragma mark - 读取图片文件数组操作 91 /** 92 * 获取来自分组(黄色文件夹)的图片数组;图片文件路径不需要包含文件夹 93 * 使用右键“Add Files to...”->“Added folders” : “Create groups”,生成分组(黄色文件夹) 94 * 95 * @return 来自分组(黄色文件夹)的图片数组 96 */ 97 - (NSArray *)imagesFromGroups { 98 NSMutableArray *mArrImgForAnimation = [[NSMutableArray alloc] initWithCapacity:kImgCount]; 99 NSString *strImgName; 100 for (NSUInteger i=0; i<kImgCount; i++) { 101 strImgName = [NSString stringWithFormat:(i<10 ? @"Happy000%lu" : @"Happy00%lu") 102 , (unsigned long)i]; 103 //[mArrImgForAnimation addObject:[UIImage imageNamed:strImgName]]; //[UIImage imageNamed:strImgName]会缓存图片,这里图片多,占内存过大,不建议用 104 105 //读取方式一(推荐使用): 106 NSString *path = [[NSBundle mainBundle] pathForResource:strImgName ofType:@"jpg"]; 107 //NSString *path = [[NSBundle mainBundle] pathForResource:strImgName ofType:nil]; //这种方式的话,strImgName的格式就为“xx.jpg” 108 109 //读取方式二: 110 //NSString *path = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:strImgName]; 111 112 //为数组mArrImgForAnimation添加数组元素 113 [mArrImgForAnimation addObject:[UIImage imageWithContentsOfFile:path]]; //虽然没缓存图片,但也可能存在内存泄露问题 114 } 115 return mArrImgForAnimation; 116 } 117 118 /** 119 * 获取来自文件夹引用(蓝色文件夹)的图片数组;图片文件路径需要包含文件夹 120 * 使用右键“Add Files to...”->“Added folders” : “Create folder references”,生成文件夹引用(蓝色文件夹) 121 * 122 * @return 来自文件夹引用(蓝色文件夹)的图片数组 123 */ 124 - (NSArray *)imagesFromFolderReferences { 125 NSMutableArray *mArrImgForAnimation = [[NSMutableArray alloc] initWithCapacity:kImgCount]; 126 NSString *strImgName; 127 for (NSUInteger i=0; i<kImgCount; i++) { 128 strImgName = [NSString stringWithFormat:(i<10 ? @"Happy000%lu" : @"Happy00%lu") 129 , (unsigned long)i]; 130 131 //读取方式一(推荐使用): 132 NSString *path = [[NSBundle mainBundle] pathForResource:strImgName ofType:@"jpg" inDirectory:@"TomCat"]; 133 //NSString *path = [[NSBundle mainBundle] pathForResource:strImgName ofType:nil inDirectory:@"TomCat"]; //这种方式的话,strImgName的格式就为“xx.jpg” 134 135 //读取方式二: 136 //NSString *bundlePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"TomCat"]; 137 //NSString *path = [bundlePath stringByAppendingPathComponent:strImgName]; 138 139 //为数组mArrImgForAnimation添加数组元素 140 [mArrImgForAnimation addObject:[UIImage imageWithContentsOfFile:path]]; //虽然没缓存图片,但也可能存在内存泄露问题 141 } 142 return mArrImgForAnimation; 143 } 144 145 @end