学习目标
1.【理解】代码创建控件过程
2.【理解】代码实现QQ登陆界面
3.【理解】图片浏览器
4.【理解】汤姆猫小游戏
一、代码创建控件过程
所有控件都是类的对象,不同的类创建可以不同类型的控件。也是就说创建一个控件其实就是创建一个对应类的对象。
常用控件类型
UIButton:按钮,界面上可点击的大都是按钮
UILabel:标签,界面上只显示文字不能点击大都是标签
UITextField:文本框,界面上可输入数据的文本框
UIImageView:图片框,界面上不可点击的图片大都是图片框
使用代码创建控件的过程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
//创建对象(控件),比如创建一个按钮(UIButton)
UIButton*btn=[[UIButtonalloc] init];
//设置这个对象(控件)的frame属性,也是控件的坐标、大小。必须给控件设置frame才能看得到
btn.frame=CGRect(50,50,100,30);//坐标为50,50 宽、高为100、30
//设置对象(控件)的一些属性
//默认、高亮状态下的按钮文字
[btn setTitle:@"登陆" forState:UIControlStateNormal];
[btn setTitle:@"点击了登陆" forState:UIControlStateHighlighted];
//默认、高亮状态下的按钮背景颜色
[btn setTitleColor:[UIColorblackColor] forState:UIControlStateNormal];
[btn setTitleColor:[UIColorgreenColor] forState:UIControlStateHighlighted];
//默认、高亮状态下的按钮背景图
[btnLogin setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal];
[btnLogin setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateHighlighted];
//最后将创建好的对象(控件)添加到他的父容器(父视图)中
[self.view addSubview:btn];//一定要将创建好的对象添加到父容器,否则无法显示
|
注意:
一定不要使用titleLabel去设置文本内容和颜色,因为按钮是有状态的。而状态的文本值是title里面取。所以如果为titleLabel设置文本,那和以系统不知道这个文本是那一种状态下显示的文本,干脆不显示。
二、代码实现QQ登陆界面
我们通过一个实例来对常用控件的基本属性、方法做个了解,和昨晚写的案例一样都是QQ登陆界面,不过这次使用纯代码的方式来实现。最终效果如下图:
首先还是先创建一个Single View Application,设置界面尺寸,导入案例需要用到的素材,本次素材就两个按钮背景图,自行网上搜索素材。搞好相关设置然后就可以开始编写代码了。
具体实现代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
#import "ViewController.h"
@interfaceViewController()
//QQ、密码文本框(UITextField)控件
@property(strong,nonatomic)UITextField*txtQQ;
@property(strong,nonatomic)UITextField*txtPassword;
@end
@implementationViewController
//控制器加载后会立即调此方法
-(void)viewDidLoad{
[superviewDidLoad];
//添加QQ、密码的Label
[selfaddQQLabel];
[selfaddPasswordLabel];
//添加QQ、密码的文本框
[selfaddQQTextField];
[selfaddPasswordTextField];
//添加登陆按钮
[selfaddLoginButton];
}
-(void)didReceiveMemoryWarning{
[superdidReceiveMemoryWarning];
}
//创建QQ标签(UILabel)的方法
-(void)addQQLabel{
//创建控件对象
UILabel*lblQQ=[[UILabelalloc] init];
//设置控件的frame属性
lblQQ.frame=CGRectMake(50,50,50,21);
//设置标签文本文字、字体、文字对齐方式
lblQQ.text=@"QQ";
lblQQ.font=[UIFont fontWithName:@"Arial" size:14];
lblQQ.textAlignment=NSTextAlignmentLeft;
//将创建好的对象添加到当前控制器
[self.view addSubview:lblQQ];
}
//创建密码标签(UILabel)的方法
-(void)addPasswordLabel{
//创建控件对象
UILabel*lblPassword=[[UILabelalloc] init];
//设置控件的frame属性
lblPassword.frame=CGRectMake(50,90,50,21);
//设置标签文本文字、字体、文字对齐方式
lblPassword.text=@"密码";
lblPassword.font=[UIFont fontWithName:@"Arial" size:14];
lblPassword.textAlignment=NSTextAlignmentLeft;
//将创建好的对象添加到当前控制器
[self.view addSubview:lblPassword];
}
//创建QQ文本框(UITextField)的方法
-(void)addQQTextField{
//创建控件对象,因为文本框中的数据需要在其他地方访问,所以就设置为属性
self.txtQQ=[[UITextFieldalloc] init];
//设置控件的frame属性
self.txtQQ.frame=CGRectMake(100,45,250,30);
//设置文本框边框样式、默认文本框内文字、清除文本内容按钮
self.txtQQ.borderStyle=UITextBorderStyleRoundedRect;
self.txtQQ.placeholder=@"请输入QQ";
self.txtQQ.clearButtonMode=UITextFieldViewModeWhileEditing;
//设置键盘类型
self.txtQQ.keyboardType=UIKeyboardTypeNumberPad;
//将创建好的对象添加到当前控制器
[self.view addSubview:self.txtQQ];
}
//创建密码文本框(UITextField)的方法
-(void)addPasswordTextField{
//创建控件对象,因为文本框中的数据需要在其他地方访问,所以就设置为属性
self.txtPassword=[[UITextFieldalloc] init];
//设置控件的frame属性
self.txtPassword.frame=CGRectMake(100,85,250,30);
//设置文本框边框样式、默认文本框内文字、清除文本内容按钮
self.txtPassword.borderStyle=UITextBorderStyleRoundedRect;
self.txtPassword.placeholder=@"请输入密码";
self.txtPassword.clearButtonMode=UITextFieldViewModeWhileEditing;
//设置密码文本框的数据密文显示(密码看不到明文文字)
[self.txtPassword setSecureTextEntry:YES];
//将创建好的对象添加到当前控制器
[self.view addSubview:self.txtPassword];
}
//创建登陆按钮(UIButton)的方法
-(void)addLoginButton{
//按钮的UIButtonType属性是只读的,只能在创建的时候初始化,如果没有设置,默认是UIButtonTypeCustom。
UIButton*btnLogin=[UIButton buttonWithType:UIButtonTypeCustom];
//设置控件的frame属性
btnLogin.frame=CGRectMake(170,130,100,30);
//分别设置按钮默认、高亮状态下的文字、文字颜色、背景图片
[btnLogin setTitle:@"登陆" forState:UIControlStateNormal];
[btnLogin setTitle:@"点击了登陆" forState:UIControlStateHighlighted];
[btnLogin setTitleColor:[UIColorblackColor] forState:UIControlStateNormal];
[btnLogin setTitleColor:[UIColorgreenColor] forState:UIControlStateHighlighted];
//背景图先拖到Assets.xcassets或者Images.xcassets里,注意是.png格式的图片
[btnLogin setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal];
[btnLogin setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateHighlighted];
//设置按钮背景颜色,有背景图了背景颜色就可以不用设置了
[btnLogin setBackgroundColor:[UIColorgrayColor]];
//为按钮添加绑定事件(单击事件),让按钮被点击后执行click方法
/*
第一个参数:调用谁的方法,让谁进行处理.往往就是self
第二个参数:调用的方法
第三个参数:事件类型
可以让多个按钮绑定同一个事件,通过tag值进行按钮的区分
*/
[btnLogin addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];
//将创建好的对象添加到当前控制器
[self.view addSubview:btnLogin];
}
//登陆按钮的单击事件
-(void)click{
//点击登录按钮后收起键盘
[self.view endEditing:YES];
NSString*msg=[NSString stringWithFormat:@"QQ:%@ 密码:%@",self.txtQQ.text,self.txtPassword.text];
//在控制台输出用户输入的QQ号、密码
NSLog(@"%@",msg);
}
@end
|
总结:
要学会如何使用代码创建控件,首先得了解代码创建控件的基本过程(创建对象、设置对象的属性、添加对象到父容器)。并且还应该了解不同控件的一些必要属性和方法,这和我们前面OC中学习的创建对象、调用方法是没有任何区别的。
三、图片浏览器
这个案例的主要目的是熟悉UIButton和UIImageView的使用,通过这个案例要全面了按钮的常用属性的设置,添加的业务逻辑也会提升我们对代码的熟练程度。同时加强封装的思想,初步使用外部的plist文件,这在之后plist文件会频繁的使用。
UIButton:当点击图片后能够有相应操作,或者点击后有高亮效果就使用UIButton。
UIImageView:当仅仅是静态展示图片,不需要对图片进行相应的操作就使用UIImageView。
下图就是我们案例完成后的样子,点击左右按钮能够切换图片、图片对应标题和索引,第一张和最有一张有按钮禁用。
创建好项目导入需要用到的图片素材,再次强调Assets.xcassets中只能放png格式的图片,在使用时省略扩展名。
拖拽两个Label控件、两个Button控件、一个Image View控件,并调整到尺寸、按钮默认、高亮背景图等等。
通过控件连线,定义好对应属性、方法,还有数组和图片索引用于操作我们的图片资源。
新建一个Property List(.plist)文件,用于封装数据。
然后选择创建好的img.plist文件,创建如下图所示的plist文件。一个数组里有5个字典,每个字典有两个键值对,img、title是键,分别对应图片名称、图片文字描述内容。
图片浏览器代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
#import "ViewController.h"
@interfaceViewController()
//存储图片资源的数组
@property(strong,nonatomic)NSArray*arrayImgs;
//图片
@property(weak,nonatomic)IBOutletUIImageView*img;
//图片顶部标签
@property(weak,nonatomic)IBOutletUILabel*topTitle;
//图片底部标签
@property(weak,nonatomic)IBOutletUILabel*downTitle;
//上下页按钮
@property(weak,nonatomic)IBOutletUIButton*preBtn;
@property(weak,nonatomic)IBOutletUIButton*nextBtn;
//图片索引
@property(assign,nonatomic)intindex;
//上一页按钮
-(IBAction)pre;
//下一页按钮
-(IBAction)next;
@end
@implementationViewController
-(void)viewDidLoad{
[superviewDidLoad];
//初始化让下标等于-1
self.index=-1;
//然后调用next方法,下标增加1。并显示下标为0的图片
[selfnext];
}
-(void)didReceiveMemoryWarning{
[superdidReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//懒加载
-(NSArray*)loadImgs{
if(_arrayImgs==nil){
//如果_arrayImgs为nil则加载img.plist文件中的数组赋值给属性
//plist文件是物理文件,所以需要获取文件目录,通过目录+文件名进行数据读取
_arrayImgs=[NSArray arrayWithContentsOfFile:[[NSBundlemainBundle] pathForResource:@"img.plist" ofType:nil]];
/*
[NSBundle mainBundle] 返回app安装后的根目录
arrayWithContentsOfFile:pathForResource:ofType:方法读取plist文件,返回一个数组
*/
}
return_arrayImgs;
}
//上一页按钮
-(IBAction)pre{
//数组下标自减,并调用方法显示图片等信息
self.index--;
[selfshowImg];
}
//下一页按钮
-(IBAction)next{
//数组下标自增,并调用方法显示图片等信息
self.index++;
[selfshowImg];
}
//显示图片
-(void)showImg{
//调用loadImgs方法初始化arrayImgs,并取出对应下标的字典
NSDictionary*dict=self.loadImgs[self.index];
//设置图片
self.img.image=[UIImage imageNamed:dict[@"img"]];
//设置图片顶部标题
self.topTitle.text=[NSString stringWithFormat:@"%d/%lu",self.index+1,self.arrayImgs.count];
//设置图片底部标题
self.downTitle.text=dict[@"title"];
//判断按钮是否可点击
//如果下标不为0,则返回YES给上一页按钮的enabled属性,否则反之
self.preBtn.enabled=self.index!=0;
//如果下标不等于数组最大下标,则返回YES给下一页按钮的enabled属性,否则反之
self.nextBtn.enabled=self.index!=self.arrayImgs.count-1;
}
@end
|
使用plist文件的好处
1.数据被封装,不再暴露在外面。
2.如果想修改或者添加删除数据,不需要修改源代码,只需要修改外部的plist文件。
3.plist文件的本质就是XML文件,所以后期可以通过对XML文件的读写操作来完成一些数据持久化操作。
创建plist文件的注意事项
1.一个字典中可以有多个key—value,多个字典包含在一个数组中。
2.plist文件名称最好不要包含info,否则会认为是系统的plist文件。
3.plist文件是物理文件,所以需要获取文件目录,通过目录+文件名进行数据读取。
获取plist文件所在的文件全路径
1
|
NSString*path=[[NSBundlemainBundle] pathForResource:@"img.plist" ofType:nil];
|
读取plist中的数据存储到数组中
1
|
self.arrayImgs=[NSArray arrayWithContentsOfFile:[[NSBundlemainBundle] pathForResource:@"img.plist" ofType:nil]];
|
四、帧动画之汤姆猫
这个案例的主要目的是了解什么是帧动画,同时掌握UIImageView的使用方式,为UIImageView控件添加动画效果和一般动画效果的添加及相关的参数设置。
png图片:一般存放在Images.xcassets中,同时在使用图片的时候不需要添加扩展名。
JPG图片:一般图片存储在Supporting Files下面,在使用jpg图片的时候一般添加扩展名。
创建项目并拖拽好各种控件,这里是先拖一个UIImageView控件占满整个屏幕,然后再为Image属性设置一张默认图片。然后拖拽6个图片按钮、3个没有任何样式的按钮(头部、双脚),并设置相关属性。
将Button用到的png格式图片拖拽到Images.xcassets,其他图片拖拽到Supporting Files,这些文件夹里包含了大量图片。
实现代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
#import "ViewController.h"
@interfaceViewController()
@property(weak,nonatomic)IBOutletUIImageView*imageViewCat;
-(IBAction)drink;//喝牛奶
-(IBAction)fart;//放屁
-(IBAction)eat;//吃鸟
-(IBAction)scratch;//爪子挖屏幕
-(IBAction)pie;//扔馅饼
-(IBAction)cymbal;//敲锣
-(IBAction)knockout;//摸头
-(IBAction)footRight;//摸右脚
-(IBAction)footLeft;//摸左脚
@end
@implementationViewController
-(void)viewDidLoad{
[superviewDidLoad];
}
-(void)didReceiveMemoryWarning{
[superdidReceiveMemoryWarning];
}
//每一个按钮所触发的动画效果类似,只有图片名称及数量不一样,所以将其封装为方法
-(void)showImageDataswithCount:(int)count andImageName:(NSString*)imageName{
//判断当前是否正在运行另外一个动画
if(self.imageViewCat.isAnimating){
return;
}
/*
将图片资源存储到数组中
UIImageView动画效果需要为其animationImages属性指定包含图片路径或者文件名的数组
所以我们首先需要获取到图片资源数组
*/
NSMutableArray*arrayM=[[NSMutableArrayalloc] init];
for(inti=0;i<count;i++){
//拼接每一张图片名称
NSString*imgName=[NSString stringWithFormat:@"%@_%02d.jpg",imageName,i];
/*
使用包含图片名称的数组做为动画的数据源会将图片资源生成缓存,占用系统内存,这样不合理.
应该使用图片的全路径数组,这样不会生成缓存,同时还应该在一个动画播放完毕后将其及时释放
*/
//UIImage *img = [UIImage imageNamed:imgName];
//图片资源放在Supporting Files
NSString*path=[[NSBundlemainBundle] pathForResource:imgName ofType:nil];
//这种方式加载的图片不会有缓存,每次用完就清空
UIImage*img=[UIImage imageWithContentsOfFile:path];
//存储到可变数组中
[arrayM addObject:img];
}
//将图片资源数组赋值给animationImages属性
self.imageViewCat.animationImages=arrayM;
//设置UIImageView的一些相关的动画属性
//设置动画时间
self.imageViewCat.animationDuration=arrayM.count *0.1;
//动画循环次数
self.imageViewCat.animationRepeatCount=1;
//动画开始播放
[self.imageViewCat startAnimating];
//动画播放完销毁,延迟执行代码
[self.imageViewCat performSelector:@selector(setAnimationImages:) withObject:nil afterDelay:arrayM.count *0.1];
}
//吃鸟
-(IBAction)eat{
[self showImageDataswithCount:40 andImageName:@"eat"];
}
//喝牛奶
-(IBAction)drink{
[self showImageDataswithCount:81 andImageName:@"drink"];
}
//放屁
-(IBAction)fart{
[self showImageDataswithCount:28 andImageName:@"fart"];
}
//爪子挖屏幕
-(IBAction)scratch{
[self showImageDataswithCount:56 andImageName:@"scratch"];
}
//扔馅饼
-(IBAction)pie{
[self showImageDataswithCount:24 andImageName:@"pie"];
}
//敲锣
-(IBAction)cymbal{
[self showImageDataswithCount:13 andImageName:@"cymbal"];
}
//摸头
-(IBAction)knockout{
[self showImageDataswithCount:81 andImageName:@"knockout"];
}
//摸右脚
-(IBAction)footRight{
[self showImageDataswithCount:30 andImageName:@"footRight"];
}
//摸左脚
-(IBAction)footLeft{
[self showImageDataswithCount:30 andImageName:@"footLeft"];
}
@end
|
最终效果如下图,由于动画图片太大就么有整动态图:
常见错误
1. jpg文件没有添加扩展名。
2. 读取全路径的jpg素材文件的时候却没有将jpg没有添加到 Supporting Files造成无法获取到。
3. 清空资源的时候没有关注self是实际含义.
注意事项
1. 使用图片文件全路径而不是使用图片名称。
2. 动画播放完毕之后及时将当前图片资源释放。
3. 拼接生成正确的文件名。
4. 在制作动画的时候,如果想设置其它属性注意要先设置好其它属性再开始动画,否则可能动画没有效果。