一、实现概述
使用一系列图像和一个UIImageView实例创建一个循环动画,还将使用一个滑块(UISlider)让用户能设置动画的播放速度,并使用UILabel显示当前的速度;另外使用步进控件(UIStepper)提供了另一种以特定的步长调整速度的途径;用户可以使用按钮播放/停止动画。
二、创建项目
选择Single View Application,选择复选框Use Storyboard和Use Automatic Reference Counting。
1、添加动画资源:将5张图片添加到项目中,在Xcode提示时,务必选择必要时复制资源并新建编组。
2、规划变量和连接:
(1)5个UIImageView显示动画的5个图片,分别通过view1、view2、view3、view4、view5引用这些图像视图;
(2)使用滑块控件(UISlider)设置播放速度,连接到speedSlider,而将播放速度本身输出到一个名为perSecond的UILabel中;
(3)使用步进控件(UIStepper)提供另一种控制速度的途径,将通过speedStepper来访问它;
(4)用于开始和暂停动画的按钮,将连接到输出口toggleButton。
注:按钮为什么也需要输出呢?
在不适用输出的时候,也可以使用按钮,但是通过将其连接到一个输出口,可轻松地在代码中设置按钮的标题。
三、设计界面
对于5个动画,由于实际上都是一样的,所以只需要创建一个,再复制即可。
1、添加UIImageView
打开MainStoryboard.storyboard,再打开对象库,并拖曳一个图像视图到应用程序的视图中。调整大小,如图所示:
(1)设置默认图像:选择UIImageView,打开Attributes Inspector,从右边的image属性下拉列表中选择一张图片资源,作为动画播放前显示。
(2)复制UIImageView:创建上诉试图的4个副本,方法是:在UI中选择该试图,再选择菜单的Edit->Duplicate(Command+D)。调整这些副本的大小和位置,使之分布在原来试图的两侧。可以设置alpha属性改变它们的透明度。
注:要想支持Retina屏幕加载的高清图片,只需要在原先的图片大小上面,添加水平和垂直分辨率都为原先2倍的图像,并使用原先的名字,后面加上@2X即可,然后加入到项目资源中。在项目中,只需要指定低分辨率的图片,必要时讲自动加载高分辨率图片。
2、添加滑块
拖曳UISlider到视图中,放在图片的下面,并在它左边添加个便签,用于显示数值;
设置最小、最大、当前值分别为:0.25、1.75、1;
注:动画速度是通过图像试图的animationDuration属性设置的,表示动画播放一次需要多少秒。这说明动画播放的速度越快,则该属性的值越小,反正则越大。这与传统的左边表示“慢”右边表示“快”刚好相反,因此需要倒转该标尺,即当滑块位于最左边的时候,animationDuration值应该最大。
反转标尺:将标尺的最小值和最大值相加(0.25+1.75=2),减去滑块当前返回的数值,这样当滑块返回的是1.75的时候,计算得到的应该是2-1.75=0.25,刚好实现了反转。
确保没有勾选Continuous:如果勾选了,则当用户来回拖曳滑块的时候,将导致滑块产生一系列事件,如果没有勾选,则仅当用户松开手指的时候才会生成事件。本程序不需要勾选,还可以节约更少的资源占用率。
还可以给滑块两端添加自定义的图片:Min Image和Max Image下拉列表。
3、添加步进控件
拖曳UIStepper到视图中,放在滑块下面。
(1)设置取值范围:这里设置和滑块的一样,将Step设置为0.25,表示每次改变的值。
取消勾选Autorepeat:如果勾选,则当用户按住不放的时候,其取值将会不断的变化;
取消勾选Continous:这样仅当用户结束与控件交互的时候才会触发事件;
勾选Wrep:超过最大值的时候,将会自动设置value为最小可能值,反之亦然,这样步进控件的取值将循环变化;如果取消勾选,则达到最大最小值的时候,值将不再变化。
4、添加标签和按钮
最后添加标签,用于显示信息;添加按钮,用于开始暂停动画。
注:如果希望进一步美化界面,可以在文档大纲区域选择View图标,再右边的属性中选择background,改变整个试图的背景颜色;
除了改变颜色,还可以再添加一个UIImageView,调整大小为全屏,再菜单Editor->Arrange->Send to Back将显示背景的UIImageView设置为动画试图的后面。
最后创建的界面如下图所示:
四、创建并连接到输出口和操作
需要创建的输出口有:
显示动画的UIImageView:view1、view2、view3、view4、view5;
设置播放速度的滑块:speedSlider;
设置播放速度的步进控件:speedStepper;
显示播放进度值的标签:perSecond;
开始/停止播放的按钮:toggleButton;
需要创建的操作有:
在用户单机按钮开始/停止的时候播放/暂停动画:toggleAnimation;
在用户拖动滑块时设置速度:setSpeed;
在用户单机步进控件时设置速度:setIncrement。
打开storyboard,切换到助手编辑模式,这样将会并排显示UI设计和ViewController.h文件。
1、添加输出口
按住Control键,从图像试图拖曳到.h文件的@interface指令下面;
在Xcode弹出的提示框中,选择类型设置为输出口,名称为view1,并保留其它默认设置;
重复其它控件,依次添加到上一个的@property下面,添加滑块的输出口为speedSlider,添加步进控件的输出口为speedStepper,添加显示播放速度的标签的输出口为perSecond,添加按钮的输出口为toggleButton。
2、添加操作
第一个操作是播放按钮,按住Control键,拖动到属性声明下面,设置类型为Action,名称为toggleAnimation,保留其它设置为默认值;
第二个操作是滑块,按住Control键,拖动到第一个IBAction声明的下方,创建一个名为setSpeed的操作,它由滑块的Value Changed事件触发;
第三个操作是步进控件,名称为setIncrement,由步进控件的Value Changed事件触发。
ViewController.h的代码如下:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (strong, nonatomic) IBOutlet UIImageView *view1;
@property (strong, nonatomic) IBOutlet UIImageView *view2;
@property (strong, nonatomic) IBOutlet UIImageView *view3;
@property (strong, nonatomic) IBOutlet UIImageView *view4;
@property (strong, nonatomic) IBOutlet UIImageView *view5;
@property (strong, nonatomic) IBOutlet UISlider *speedSlider;
@property (strong, nonatomic) IBOutlet UIStepper *speedStepper;
@property (strong, nonatomic) IBOutlet UILabel *perSecond;
@property (strong, nonatomic) IBOutlet UIButton *toggleButton;
- (IBAction)toggleAnimation:(id)sender;
- (IBAction)setSpeed:(id)sender;
- (IBAction)setIncrement:(id)sender;
@end
五、实现程序逻辑
1、让UIImageView显示动画
要让UIImageView显示动画,需要创建一个图像对象(UIImage)数组,并将它们传递给UIImageView对象。
打开ViewController.m文件,找到ViewDidLoad方法,在其中添加如下代码:
- (void)viewDidLoad
{
//添加动画资源-图像数组
NSArray *hopAnimation;
hopAnimation = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:@"Icon_a.png"],
[UIImage imageNamed:@"Icon_b.png"],
[UIImage imageNamed:@"Icon_a.png"],
[UIImage imageNamed:@"Icon_c.png"],
[UIImage imageNamed:@"Icon_d.png"],nil];
self.view1.animationImages = hopAnimation;
self.view2.animationImages = hopAnimation;
self.view3.animationImages = hopAnimation;
self.view4.animationImages = hopAnimation;
self.view5.animationImages = hopAnimation;
//设置动画播放一次的持续时间,默认为30帧/秒
self.view1.animationDuration = 1;
self.view2.animationDuration = 1;
self.view3.animationDuration = 1;
self.view4.animationDuration = 1;
self.view5.animationDuration = 1;
[super viewDidLoad];
}
上述代码首先声明了一个数组,分配内存初始化图像对象(UIImage)并将其加入到数组中。使用图像对象填充到数组后,接下来就可以使用它来设置UIImageView的动画,这里将UIImageView的animationImages属性设置为该数组对象。
设置初始的动画持续时间属性都为1。
2、开始和停止动画播放
isAnimation:如果UIImageView正在以动画的形式播放其内容,则返回true;
startAnimation:开始播放动画;
stopAnimation:停止播放动画。
当用户点击按钮的时候,将会触发toggleAnimation方法,这个方法应该使用UIImageView之一(如view1)的isAnimation属性判断当前是否在播放,如果没有,则应该开发,否则应该停止。并且更改按钮显示。
//播放或者暂停动画按钮点击事件
- (IBAction)toggleAnimation:(id)sender {
if (view1.isAnimating) {
[self.view1 stopAnimating];
[self.view2 stopAnimating];
[self.view3 stopAnimating];
[self.view4 stopAnimating];
[self.view5 stopAnimating];
[self.toggleButton setTitle:@"变!" forState:UIControlStateNormal];
} else {
[self.view1 startAnimating];
[self.view2 startAnimating];
[self.view3 startAnimating];
[self.view4 startAnimating];
[self.view5 startAnimating];
[self.toggleButton setTitle:@"停!" forState:UIControlStateNormal];
}
}
使用UIButton的实例方法:setTittle:forState分别更改当前按钮显示,在按钮的正常状态下更改,表示的是当前用户没有按下按钮的正常状态。
3、设置动画播放速度
//滑块控件触发的方法
- (IBAction)setSpeed:(id)sender {
NSString *hopRateString;
self.view1.animationDuration = 2 - self.speedSlider.value;
self.view2.animationDuration = self.view1.animationDuration
+ ((float)(rand() % 11 + 1) / 10);
self.view3.animationDuration = self.view1.animationDuration
+ ((float)(rand() % 11 + 1) / 10);
self.view4.animationDuration = self.view1.animationDuration
+ ((float)(rand() % 11 + 1) / 10);
self.view5.animationDuration = self.view1.animationDuration
+ ((float)(rand() % 11 + 1) / 10);
[self.view1 startAnimating];
[self.view2 startAnimating];
[self.view3 startAnimating];
[self.view4 startAnimating];
[self.view5 startAnimating];
[self.toggleButton setTitle:@"正在变换" forState:UIControlStateNormal];
hopRateString = [[NSString alloc] initWithFormat:@"%1.2f hps",1 / (2 - self.speedSlider.value)];
self.preSecond.text = hopRateString;
}
设置其它图像视图的动画播放速度比view1慢个零点几秒;
使用startAnimation开始,这个方法即使当前正在播放也不会出错,因此不需要去判断当前是否在播放;
当前动画速度:动画速度是以秒为单位的,最快的为0.25秒,表示每秒钟播放4次,所以表示速度的,计算公式为:1 / (2 - speedSlider.value);
4、调整动画播放速度
//步进控件点击事件
- (IBAction)setIncrement:(id)sender {
self.speedSlider.value = self.speedStepper.value;
[self setSpeed:nil];
}
@end
由于设置的步进控件的取值范围和滑块的一样,所以只需要将滑块的值设置为步进控件的值就行,然后手动去调用setSpeed方法。
由于滑块的value被设置为步进控件的value,这将导致界面的滑块也发生相应的更新,但是,不会触发其Value Changed事件而调用setSpeed方法。因此,需要手动去给视图控制器对象发送setSpeed消息。
注:在调用setSpeed时,传递了参数nil。在默认情况下,操作方法接受一个sender参数,该参数自被自动设置为触发操作的对象。这样,操作就可以查看sender,并做出相关的响应。在setSpeed中,从未使用sender,因此只需要将其设置为nil,满足调用该方法的要求即可。
六、实现代码总结
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
@synthesize view1;
- (void)viewDidLoad
{
//添加动画资源-图像数组
NSArray *hopAnimation;
hopAnimation = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:@"Icon_a.png"],
[UIImage imageNamed:@"Icon_b.png"],
[UIImage imageNamed:@"Icon_a.png"],
[UIImage imageNamed:@"Icon_c.png"],
[UIImage imageNamed:@"Icon_d.png"],nil];
self.view1.animationImages = hopAnimation;
self.view2.animationImages = hopAnimation;
self.view3.animationImages = hopAnimation;
self.view4.animationImages = hopAnimation;
self.view5.animationImages = hopAnimation;
//设置动画播放一次的持续时间,默认为30帧/秒
self.view1.animationDuration = 1;
self.view2.animationDuration = 1;
self.view3.animationDuration = 1;
self.view4.animationDuration = 1;
self.view5.animationDuration = 1;
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//播放或者暂停动画按钮点击事件
- (IBAction)toggleAnimation:(id)sender {
if (view1.isAnimating) {
[self.view1 stopAnimating];
[self.view2 stopAnimating];
[self.view3 stopAnimating];
[self.view4 stopAnimating];
[self.view5 stopAnimating];
[self.toggleButton setTitle:@"变!" forState:UIControlStateNormal];
} else {
[self.view1 startAnimating];
[self.view2 startAnimating];
[self.view3 startAnimating];
[self.view4 startAnimating];
[self.view5 startAnimating];
[self.toggleButton setTitle:@"停!" forState:UIControlStateNormal];
}
}
//滑块控件触发的方法
- (IBAction)setSpeed:(id)sender {
NSString *hopRateString;
self.view1.animationDuration = 2 - self.speedSlider.value;
self.view2.animationDuration = self.view1.animationDuration
+ ((float)(rand() % 11 + 1) / 10);
self.view3.animationDuration = self.view1.animationDuration
+ ((float)(rand() % 11 + 1) / 10);
self.view4.animationDuration = self.view1.animationDuration
+ ((float)(rand() % 11 + 1) / 10);
self.view5.animationDuration = self.view1.animationDuration
+ ((float)(rand() % 11 + 1) / 10);
[self.view1 startAnimating];
[self.view2 startAnimating];
[self.view3 startAnimating];
[self.view4 startAnimating];
[self.view5 startAnimating];
[self.toggleButton setTitle:@"正在变换" forState:UIControlStateNormal];
hopRateString = [[NSString alloc] initWithFormat:@"%1.2f hps",1 / (2 - self.speedSlider.value)];
self.preSecond.text = hopRateString;
}
//步进控件点击事件
- (IBAction)setIncrement:(id)sender {
self.speedSlider.value = self.speedStepper.value;
[self setSpeed:nil];
}
@end