【汤姆猫的实现 Objective-C语言】

本文详细介绍了如何使用Objective-C实现汤姆猫应用的动画效果,包括背景图片框的设置、帧动画原理、UIImageView的animationImages属性、动画持续时间、重复次数的设置以及如何启动和停止动画。通过加载一系列图片并快速切换,实现了汤姆猫各种动作的动画效果,如喝牛奶、抓屏幕等。

一、实现之后的效果

汤姆猫

1.左边3个按钮,分别是

1)点击之后,汤姆猫掏出一只白色的小鸟,刚要吃,它飞走了,

2)汤姆猫放屁

3)汤姆猫喝牛奶,

右边3个按钮,分别是

1)汤姆猫用爪子把屏幕抓出3个道子,

2)汤姆猫用披萨饼砸屏幕,

3)汤姆猫拿出两个锣,对着一敲,

2.这些动画怎么实现的,

是不是很多很多图片顺序播放啊,

很多图片快速的切换,然后你眼睛感觉是不是它们就在动吧,

3.所以,这个app实现的方式,就是背景放一个大的图片框,

为什么是图片框,而不是按钮,

需要点吗,背景,不需要,

点一下,疑,有用了,汤姆猫被打倒了…

说明我在这儿放了一个透明的按钮,

其实,整个这儿背景是一个图片框,你点是没有用的,

它需要放一张图片,又不需要点击,

所以说,这儿用一个图片框就可以了,

4.左边3个按钮,右边3个按钮,也是小图片,

但是这些能点,说明这6个是什么啊,按钮吧

当你点击某个按钮的时候,我就通过动画的方式,快速的切换这个图片框中的每1张图片,

这样的话,看起来就是一个动画了,

5.看一下Supporting Files里面的素材,

1)Angry文件夹,是汤姆猫“生气”的动画,是一大堆图片,单看每一张没什么效果,但是快速切换的时候,就能看到汤姆猫生气的动画了

2)要实现这个效果,首先,我先把素材拷进来,

我们这里用到的素材,一个就是这些图片,再一个,就是这个tom.plist文件,

我们先把图片素材拷进来,

找到我们这个素材文件夹,找到里面的汤姆猫文件夹,找到里面的Animations文件夹,这些是不是我们具体使用的一些图片啊,

在以前xcode5的时候,只有这个图片是png图片的时候,才可以直接拷到images.xcassets文件夹下,

但是在xcode6的时候,你这个图片是jpg的图片,也可以直接拷到这个images.xcassets文件夹下,

只要是图片,都可以拷过来,

这是我们动画图片,

这个Buttons,是我们的按钮图片,

然后我把Animations文件夹,和Buttons文件夹,一起拽到我的Xcode的images.xcassets文件夹下,

接下来,我们就尝试把这个汤姆猫做一下,看一看怎么做

二、实现汤姆猫app,

1.打开storyboard,

选中控制器,size调成4.7inch,

2.背景放一个大的图片框,UIImageView控件,

让它充满整个屏幕,

我给它先来一张默认图,例如,来一个angry_00

这是在imageView右边的属性控制器里实现的,找到它的image属性,给个angry_00,

接下来,我们实现动画,就是要让这些图片,快速的切换,

我们已经学了两种动画方式,

一种是“头尾试”

通过调UIView的一个类方法,beginAnimation,

和一个setAnimationDuration,

以及commitAnimation,

通过这3个方法,可以执行一个“头尾式”动画吧,

第二种是调UIView的一个animateWithDuration,那个block方式,

接下来,我们要实现的这个汤姆猫的动画,跟前面那两个没关系,

这个不是说要让它的位置从一个地方移动到另一个地方,大小变化,在动画里面执行,不是这个意思,

现在的动画是,要让这个图片框,快速的切换图片,实现的动画,

3.这个动画的实现思路是这样的,

我们首先这个图片是在一个UIImageView,一个图片框里面吧,我们通过调图片框的一些方法,那么这个时候,图片框会把在图片框里面的图片,它自己会做动画,我们只要调图片框这个对象的一些方法,就ok了,

这个是完全通过图片框自己实现的,

和那两个动画没有关系,

4.那么接下来,我们看一下,这个图片框是怎么实现动画呢,

我们说,这个动画,叫做

UIImageView帧动画,

就是让图片框里面的图片一张一张变的动画,

既然它要让图片框里面的图片一张一张变,

你想想,这个图片框里面能只有1张图片吗,

1张图片,你再怎么变,它也不会动吧,

所以说,第一个,是要告诉这个图片框,它里面,有哪些图片,就是给它的animationImages,给这个属性设置值,

@property(nonatomic,copy) NSArray *animationImages;

这个属性,是1个什么类型的属性,数组类型吧,

意味着,我们一开始,要把所有的图片,加载到这个数组里面,

也就是说,这个图片框,它首先有一个数组,这个数组里面,保存了它要执行动画的所有的图片,

@property(nonatomic,copy) NSArray *animationImages;

那为什么@property的参数要用copy,是不是不希望把数组赋值给下划线属性之后,如果修改了赋值之前的数组,下划线属性也会跟着修改啊,不希望下划线属性跟着修改啊,所以用copy,深拷贝一份数组,然后赋值给下划线属性,

当然NSArray是不能修改的,但如果有时候是把NSMutableString赋值给这个下划线属性呢,是不是赋值前的变量就可以修改了,如果一修改,下划线属性就跟着改,这肯定是不好的,所以这里要用copy参数,深拷贝一份,然后赋值给下划线属性,

setter方法是这样写的:

- (void)setAnimationImages:(NSArray *)animationImages{

_animationImages = [animationImages copy];

}

这就好比Person类的一个属性是name,它是一个NSString类型的,但是有时候会把NSMutableString类型的字符串赋值给它,不希望赋值前的变量修改的时候,这个Person的name属性也跟着修改,所以NSString类型的属性,不论是在ARC还是在MRC下,都要用copy参数写property,

@property(nonatomic,copy)NSString *name;

这时候,setter方法是这样的,

- (void)setName:(NSString *)name{

_name = [name copy];

}

这样写,是把赋值前的变量name,深拷贝一份,赋值给_name属性,

因为NSString,在copy的时候,是浅拷贝,因为NSString修改的时候,是立刻生成一个新的字符串,所以不会影响Person的name属性,

但是NSMutableString,在copy的时候,是深拷贝,所以拷贝出来一个对象,赋值给Person的name属性,赋值前的变量即使修改,也不影响Person的name属性,

NSString如果用mutableCopy方法,是深拷贝,生成一个NSMutableString变量,

NSMubatleString使用mutableCopy方法,也是深拷贝,生成的还是NSMutableString变量,

3.好了,这是第一步,设置

@property(nonatomic,copy)NSArray *animationImages;

属性,这个属性的作用,是

需要播放的序列帧图片数组(里面都是UIImage对象,会按顺序显示里面的图片),

4.第二步,你告诉这个图片框,你这个动画要执行多长时间呢,

用这个属性,

@property(nonatomic)NSTimeInterval animationDuration;

帧动画的持续时间,

比如说,喝牛奶这个动画,要在10秒钟完成,它是不是很慢,

我如果1秒钟执行完,它是不是立刻就喝完了,

也就是说,这个animationDuration,就是告诉图片框,切图片的时候,这个时间,用多长时间来切,

这个时间越短,动画看起来越快,

这个时间越长,动画看起来越快,

所以说,要让图片框里面的图片快速切换,实现动画,

第一,告诉图片框,哪些图片要实现动画,

第二,告诉图片框,动画持续时间,

第三,告诉图片框,这个动画是不是要重复播放,

也就是说给这个属性赋值:

@property(nonatomic) NSInteger animationRepeatCount;

帧动画的执行次数(默认是无限循环)

如果这个动画重复播放,你告诉它“是”的话,

它在播放完一遍以后,紧接着第二遍继续播放,永不停止,一直重复播放,

但是我们要的是这个效果吗,不是,

所以这个animationRepeat,Repeat是重复的意思,这个animationRepeatCount,等于是“YES”还是“NO”,“NO”吧,不让它重复,

第四步,紧接着,你这些基本的条件都设置好以后,这个图片框知道它里面要显示的是哪些图片,它知道这个动画要执行多长时间,它也知道是否要重复啦,

接下来,就该怎么办了,

startAnimating,是不是启动动画啊,用这个方法:

- (void)startAnimating;

开始执行帧动画,

第五步,比如说,动画启动以后,还没有执行完毕,就想让动画停止,怎么办,

用这个stopAnimating方法,

- (void)stopAnimating;

停止执行帧动画,

第六步,想知道现在动画是否正在执行,怎么办,用这个方法:

- (BOOL)isAnimating;

是否正在执行帧动画,

6.所以说,现在要想实现这个“汤姆猫”,

1)第一步,拽一个大的图片框,

2)第二步,紧接着就是加载那一系列的图片,设置给图片框的animationImages属性,让它知道,哦,这些图片,我让它动,

3)第三步,然后我设置时间,

4)第四步,启动,

明白这一个思路了吧,

就是通过UIImageView,这个图片框的一个动画,和我们之前学的动画,是没有关系的,

三、那么,接下来看一下,要怎么做呢,

1.打开我们的这个程序,

我们现在,图片素材已经拷进来了,

但是我们还没有把这些图片加进来吧,

好,我们先不做那么多动画,

我们先做一个,

咱们先做一个“喝牛奶”,

“喝牛奶”是不是图片比较多吧,

2.既然要“喝牛奶”,这个左下角,应该摆一个“喝牛奶”的小按钮吧,

拖一个按钮进来,放到左下角,

设置一下它这个喝牛奶的图片,

1)里面的文字,是“”,不要,

2)喝牛奶这个图片叫什么啊,drink吧,

我们设置一下这个按钮吧,

注意,我设置在背景属性background也行,设置在上面这个image属性也行,

如果你上面有文字,同时还要显示图片,这个时候一般情况下设置背景属性background,

但是我如果只想显示图片的时候,设image是不是也行啊,

我为什么设置image,不设置背景呢,

因为设置了背景以后,这个按钮不会跟随图片大小而变化,

但是我如果设置image以后,这个按钮会自动调整到和这个图片一样,

所以说,为了省事儿,我就设置image了,

image属性,给个drink,

ok,它是不是自动调整大小,和图片大小一样了,

我为了用这个功能,所以就设了个image,

3)这个按钮单击的时候,我们是不是要执行一段动画啊,

所以说,给这个按钮来一个单击事件,

先把其他5个按钮给你拖进来吧,

我要给这个drink按钮注册一个单击事件,

同时,单击的时候,等会儿我们需要访问这个图片框啊,

是不是我要给这个图片框动态的设置它的一些属性,

所以说,我要通过一个属性,来引用这个图片框,

辅助编辑器,打开,自动跳到这个延展中,

选中图片框,按住control键,拖线到延展里面,

设置4个参数,

第一个参数,Connection,给个Outlet,

第二个参数,Name属性,给个imgView,

是不是图片框,来个Cat,猫,

所以,name属性,给个imgViewCat,

第三个参数,Type,给个UIImageView,

第四个属性,Storage,给个Weak,

点击Connect,自动生成了这个属性:

@property(weak,nonatomic)IBOutlet UIImageView *imgViewCat;

4)然后呢,drink按钮,拖线到延展中,设置5个参数,

第一个参数,Connection,给个Action,

第二个参数,Name,给个drink,

第三个参数,Type,给个id,

第四个参数,Event,给个Touch Up Inside,

第五个参数,Argument,给个None,

点击Connect,自动生成了这个方法:

- (IBAction)drink;

5)接下来,我们来实现这个代码,

//喝牛奶的动画,

- (IBAction)drink{

//code;

}

那么这个喝牛奶的动画,怎么来实现呢,

这个动画的思路,还记得吗,

1)动态加载图片,到一个NSArray中,

2)设置UIImageView,就是图片框,的animationImages属性,这个属性里面包含的是什么,这个属性中包含的就是所有那些要执行动画的图片,

3)设置动画持续时间,

4)设置动画是否需要重复播放,

5)开启动画,

你要给图片框设置这个属性,刚才我们是不是已经拖线,用这个imgViewCat表示这个大的图片框啊,

所以,这儿就来个self.imgViewCat.animationImages ,是不是设置这个属性啊,

要给它,给一个Array,这个NSArray里面,就包含了所有那些要执行动画的图片,

所以说,第一步,我们首先要把那些要执行动画的图片,是不是加载到一个NSArray里面,

好,注意看,现在我们是喝牛奶,喝牛奶那些图片在哪里,

我们发现,凡是喝牛奶的图片,都是drink下划线,后面跟两个索引来开头的啊,

所以说,接下来,我们就要一张一张去把图片加载起来,

并且把每张图片都放到一个数组的元素里面,

怎么样把这张图片,drink_00 ,加载到内存里面,

加载一张图片,怎么加,

UIImage *img = [UIImage imageNamed:@这儿是不是要写那个图片的名称,

UIImage *img = [UIImage imageNamed:@“drink_00”];

因为这个图片的后缀是jpg,所以我们这儿是不是要加一个jpg后缀啊,

UIImage *img = [UIImage imageNamed:@“drink_00.jpg”];

这样的话,我们是不是就把这张图片加载到内存里面了,

但是,我们现在要的是只加载一张吗,

不是,我们现在要的是加载什么啊,是不是加载所有的图片啊,

从drink_00到drink_80,

是不是加载这么多张图片啊,

请问大家,如果是你的话,你会不会把这句话写80遍?

UIImage *img = [UIImage imageNamed:@“drink_00.jpg”];

如果你会的话,我告诉你,不需要,我们是不是可以写个循环啊,

6)写个循环:

那么,我们要把这句话,放到循环里面,注意看:

UIImage *img = [UIImage imageNamed:@“drink_00.jpg”];

for(int i

for循环,i等于几,等于0,i小于几,我们是不是一共80吧,应该是小于81吧,为什么小于81呢,因为这里的图片,是不是00到80吧,是不是要用80,所以来个81,

这儿一共是几张图,81张图,对吧,

0到81,循环81次,

i怎么样,i++

for(int i=0;i<81;i++){

//statements;

}

然后这里面,这张图片是不是要有循环,是不是要加载81次,

UIImage *img = [UIImage imageNamed:@“drink_00.jpg”];

所以,把这句话剪切到for循环中,

for(int i=0;i<81;i++){

UIImage *img = [UIImage imageNamed:@“drink_00”];

}

但是,加载81次的时候,每次加载这张图,是不是要放到数组里面,

所以说,前面得有个啥,

NSArray行不行,

不行,NSMutableArray吧,

因为这个NSArray是个不可变数组,是不是要可变,

是不是每次要向里面加一张图,

所以说,这里面不能用NSArray,要用NSMutableArray,

NSMutableArray *arrayM,

一般我们后缀是M的时候,一般表示可变的,

NSMutableArray *arrayM = [NSMutableArray array];

好,这样的话,就创建了一个可变数组,

每次我们加载一张图,是不是要把这张图,放到这个数组里面,

[arrayM addObject:img];

也就是这样,

- (IBAction)drink{

//0.动态加载图片到一个NSArray中

NSMutableArray *arrayM = [NSMutableArray array];

for(int i = 0 ; i < 81 ; i++){

UIImage *img = [UIImage imageNamed:@“drink_00.jpg”];

[arrayM addObject:img];

}

这样的话,是不是就循环,把这个图加进来了,

但是,哪儿有问题,

你这是把同样的图片,是不是加了80张进来,

UIImage *img = [UIImage imageNamed:@“drink_00.jpg”];

我们这个地方,怎么才能一张一张的变,

我们是不是首先要通过NSString,给这个图片名称,是不是要动态拼接这个图片名称,

这个图片名称要动态拼接,不能写死,

NSString *imgName = [NSString stringWithFormat:@“drink_%d.jpg”,i];

这儿该怎么写啊,

这儿,我写@“drink_%d.jpg”,这儿写i,请问对还是不对,

不对,为什么不对,

因为我这儿如果是第1张的话,这儿会变成个1,drink_1.jpg,请问有drink_1.jpg这张图片吗,

没有,只有drink_01.jpg,

也就是说,你这个i,如果是小于10的话,是不是也得保留两位啊,

所以,这儿应该写%2d,保留两位,

@“drink_%2d.jpg”,i

保留两位,如果是3,是什么3,前面那个补一个几啊,

补一个0,所以是百分号零2d

@“drink_%02d.jpg”,i

是不是这么来写啊,

百分号2d,表示保留两位,

百分号零2d,表示如果要是两位,第一位如果是空的话,给它补一个零,

千万别写百分号20d,这样的话,保留20位,

%02d,这样的话,就表示i如果是个位的话,你要让它保留两位,必须得显示两位,那么第一位,如果要是空出来的话,用什么表示呢,用1个零来补齐,

这样的话,遇到0,就变成00,

遇到1,就变成01,

遇到3,就变成03,

遇到10,还是10,

因为它不是个位,不需要补,对吧,

NSString *imgName = [NSString stringWithFormat:@“drink_%02d.jpg”,i];

这样的话,就创建好了,加载好了图片,

然后,把这个地方写一个imgName,

[arrayM addObject:imgName];

for(int i=0;i<81;i++){

NSString *imgName = [NSString stringWithFormat:@“drink_%02d.jpg”,i];

[arrayM addObject:imgName];

}

好,这是不是我们就创建好这个图片了吧,

这样的话,所有的图片都有了,

并且图片都加载到这个集合里面了,arrayM,

然后,接下来怎么办,

2)我们把这个集合,把这个数组,设置给我们这个图片框的animationImages属性,

self.imgViewCat.animationImages = arrayM;

这样的话,这个图片框,就知道,我将来要把这些图片,做动画,要一张一张切换吧,

3)设置持续时间,

self.imgViewCat.animationDuration,

是不是动画持续时间,

这个动画持续时间,应该是多长啊,

1秒也行,2秒也行,3秒也行,随便你,

但是你也可以试着来一下,你这个图片框,它里面有多少张图片,

self.imgViewCat.animationImages.count,

让每张图片显示0.1秒,

self.imgViewCat.animationImages.count * 0.1

这样的话,是不是也行,

self.imgViewCat.animationDuration = self.imgViewCat.animationImages.count * 0.1;

这样的话,你有多少张图片,每张图片显示0.1秒,总的时间,是不是就是总的动画持续时间,

这样的话,相对来说是不是,就是比较,更自然一些吧,

4)然后呢,是否要重复播放呢,

self.imgViewCat.animationRepeatCount = 等于几,

这个属性的签名如下:

NSInteger animationRepeatCount

这个属性,是一个整型吧,

整型的话,重复几次,重复1次就可以了吧,

如果你不设置这个属性,它会一直重复的,

5)开启动画,

怎么开启动画,

[self.imgViewCat startAnimating];

好了,这样的话,就是

1)把图片加载到数组里面,

2)设置这个数组,给这个图片,给这个图片集合,

3)设置持续时间,

4)设置重复次数,

5)启动动画,

来,咱们看一下动画,能不能启动,

运行,

崩溃了,有一个方法未识别,

unrecognized selector sent to instance,

为什么,因为这句话,

NSString *imgName = [NSString stringWithFormat:@“drink_%02d.jpg”,I];

这个*imgName,只是一个图片的名称吧,

还没有给它加载到内存里面呢,

没有调用那句话,imageNamed,

[UIImage imageNamed:@“”];

没有调用这个方法,

UIImage *imgCat = [UIImage imageNamed:imgName];

[arrayM addObject:imgCat];

for(int i = 0 ; i < 81 ; i ++ ){

//1.拼接图片名称,

NSString *imgName = [NSString stringWithFormat:@“drink_%02d.jpg”,i];

//2.根据图片名称加载图片,

UIImage *imgCat = [UIImage imageNamed:imgName];

//3.把图片加载到数组中,

[arrayM addObject:imgCat];

}

再运行,可以了,

如果不设置重复次数,将会一直重复,

repeatCount如果没有设置,会一直重复,

repeatCount,给它来个1次,

self.imgViewCat.animationRepeatCount = 1;

这样是不是就ok了,

好了,这就是我们的图片框的帧动画是怎么实现的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清风清晨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值