1、 代码创建控件过程
所有控件都是类的对象,不同的类创建可以不同类型的控件。也是就说创建一个控件其实就是创建一个对应类的对象。
常用控件类型
UIButton:按钮,界面上可点击的大都是按钮
UILabel:标签,界面上只显示文字不能点击大都是标签
UITextField:文本框,界面上可输入数据的文本框
UIImageView:图片框,界面上不可点击的图片大都是图片框
使用代码创建控件的过程
//创建对象(控件),比如创建一个按钮(UIButton)
UIButton *btn = [[UIButton alloc] init];
//设置这个对象(控件)的frame属性,也是控件的坐标、大小。必须给控件设置frame才能看得到
btn.frame = CGRect(50,50,100,30);//坐标为50,50 宽、高为100、30
//设置对象(控件)的一些属性
//默认、高亮状态下的按钮文字
[btn setTitle:@"登陆" forState:UIControlStateNormal];
[btn setTitle:@"点击了登陆" forState:UIControlStateHighlighted];
//默认、高亮状态下的按钮背景颜色
[btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[btn setTitleColor:[UIColor greenColor] forState:UIControlStateHighlighted];
//默认、高亮状态下的按钮背景图
[btnLogin setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal];
[btnLogin setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateHighlighted];
//最后将创建好的对象(控件)添加到他的父容器(父视图)中
[self.view addSubview:btn];//一定要将创建好的对象添加到父容器,否则无法显示
注意:
一定不要使用titleLabel去设置文本内容和颜色,因为按钮是有状态的。而状态的文本值是title里面取。所以如果为titleLabel设置文本,那和以系统不知道这个文本是那一种状态下显示的文本,干脆不显示。
2、 代码实现QQ登陆界面
我们通过一个实例来对常用控件的基本属性、方法做个了解,和昨晚写的案例一样都是QQ登陆界面,不过这次使用纯代码的方式来实现。最终效果如下图:
首先还是先创建一个Single View Application,设置界面尺寸,导入案例需要用到的素材,本次素材就两个按钮背景图,自行网上搜索素材。搞好相关设置然后就可以开始编写代码了。
具体实现代码如下:
#import "ViewController.h"
@interface ViewController ()
//QQ、密码文本框(UITextField)控件
@property (strong, nonatomic) UITextField *txtQQ;
@property (strong, nonatomic) UITextField *txtPassword;
@end
@implementation ViewController
//控制器加载后会立即调此方法
- (void)viewDidLoad {
[super viewDidLoad];
//添加QQ、密码的Label
[self addQQLabel];
[self addPasswordLabel];
//添加QQ、密码的文本框
[self addQQTextField];
[self addPasswordTextField];
//添加登陆按钮
[self addLoginButton];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
//创建QQ标签(UILabel)的方法
- (void)addQQLabel {
//创建控件对象
UILabel *lblQQ = [[UILabel alloc] 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 = [[UILabel alloc] 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 = [[UITextField alloc] 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 = [[UITextField alloc] 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:[UIColor blackColor] forState:UIControlStateNormal];
[btnLogin setTitleColor:[UIColor greenColor] forState:UIControlStateHighlighted];
//背景图先拖到Assets.xcassets或者Images.xcassets里,注意是.png格式的图片
[btnLogin setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal];
[btnLogin setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateHighlighted];
//设置按钮背景颜色,有背景图了背景颜色就可以不用设置了
[btnLogin setBackgroundColor:[UIColor grayColor]];
//为按钮添加绑定事件(单击事件),让按钮被点击后执行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中学习的创建对象、调用方法是没有任何区别的。
3、 图片浏览器
这个案例的主要目的是熟悉UIButton和UIImageView的使用,通过这个案例要全面了按钮的常用属性的设置,添加的业务逻辑也会提升我们对代码的熟练程度。同时加强封装的思想,初步使用外部的plist文件,这在之后plist文件会频繁的使用。
UIButton:当点击图片后能够有相应操作,或者点击后有高亮效果就使用UIButton。
UIImageView:当仅仅是静态展示图片,不需要对图片进行相应的操作就使用UIImageView。
下图就是我们案例完成后的样子,点击左右按钮能够切换图片、图片对应标题和索引,第一张和最有一张有按钮禁用。
创建好项目导入需要用到的图片素材,再次强调Assets.xcassets中只能放png格式的图片,在使用时省略扩展名。
拖拽两个Label控件、两个Button控件、一个Image View控件,并调整到尺寸、按钮默认、高亮背景图等等。
通过控件连线,定义好对应属性、方法,还有数组和图片索引用于操作我们的图片资源。
新建一个Property List(.plist)文件,用于封装数据。
然后选择创建好的img.plist文件,创建如下图所示的plist文件。一个数组里有5个字典,每个字典有两个键值对,img、title是键,分别对应图片名称、图片文字描述内容。
图片浏览器代码实现
#import "ViewController.h"
@interface ViewController ()
//存储图片资源的数组
@property (strong, nonatomic) NSArray *arrayImgs;
//图片
@property (weak, nonatomic) IBOutlet UIImageView *img;
//图片顶部标签
@property (weak, nonatomic) IBOutlet UILabel *topTitle;
//图片底部标签
@property (weak, nonatomic) IBOutlet UILabel *downTitle;
//上下页按钮
@property (weak, nonatomic) IBOutlet UIButton *preBtn;
@property (weak, nonatomic) IBOutlet UIButton *nextBtn;
//图片索引
@property (assign, nonatomic) int index;
//上一页按钮
- (IBAction)pre;
//下一页按钮
- (IBAction)next;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//初始化让下标等于-1
self.index = -1;
//然后调用next方法,下标增加1。并显示下标为0的图片
[self next];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//懒加载
- (NSArray *)loadImgs {
if (_arrayImgs == nil) {
//如果_arrayImgs为nil则加载img.plist文件中的数组赋值给属性
//plist文件是物理文件,所以需要获取文件目录,通过目录+文件名进行数据读取
_arrayImgs = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"img.plist" ofType:nil]];
/*
[NSBundle mainBundle] 返回app安装后的根目录
arrayWithContentsOfFile:pathForResource:ofType:方法读取plist文件,返回一个数组
*/
}
return _arrayImgs;
}
//上一页按钮
- (IBAction)pre {
//数组下标自减,并调用方法显示图片等信息
self.index--;
[self showImg];
}
//下一页按钮
- (IBAction)next {
//数组下标自增,并调用方法显示图片等信息
self.index++;
[self showImg];
}
//显示图片
- (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文件所在的文件全路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"img.plist" ofType:nil];
读取plist中的数据存储到数组中
self.arrayImgs = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"img.plist" ofType:nil]];
4、 汤姆猫小游戏
这个案例的主要目的是了解什么是帧动画,同时掌握UIImageView的使用方式,为UIImageView控件添加动画效果和一般动画效果的添加及相关的参数设置。
png图片:一般存放在Images.xcassets中,同时在使用图片的时候不需要添加扩展名。
JPG图片:一般图片存储在Supporting Files下面,在使用jpg图片的时候一般添加扩展名。
创建项目并拖拽好各种控件,这里是先拖一个UIImageView控件占满整个屏幕,然后再为Image属性设置一张默认图片。然后拖拽6个图片按钮、3个没有任何样式的按钮(头部、双脚),并设置相关属性。
将Button用到的png格式图片拖拽到Images.xcassets,其他图片拖拽到Supporting Files,这些文件夹里包含了大量图片。
实现代码如下:
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageViewCat;
- (IBAction)drink;//喝牛奶
- (IBAction)fart;//放屁
- (IBAction)eat;//吃鸟
- (IBAction)scratch;//爪子挖屏幕
- (IBAction)pie;//扔馅饼
- (IBAction)cymbal;//敲锣
- (IBAction)knockout;//摸头
- (IBAction)footRight;//摸右脚
- (IBAction)footLeft;//摸左脚
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
//每一个按钮所触发的动画效果类似,只有图片名称及数量不一样,所以将其封装为方法
- (void)showImageDataswithCount:(int)count andImageName:(NSString *)imageName {
//判断当前是否正在运行另外一个动画
if (self.imageViewCat.isAnimating) {
return;
}
/*
将图片资源存储到数组中
UIImageView动画效果需要为其animationImages属性指定包含图片路径或者文件名的数组
所以我们首先需要获取到图片资源数组
*/
NSMutableArray *arrayM = [[NSMutableArray alloc] init];
for (int i = 0; i < count; i++) {
//拼接每一张图片名称
NSString *imgName = [NSString stringWithFormat:@"%@_%02d.jpg",imageName,i];
/*
使用包含图片名称的数组做为动画的数据源会将图片资源生成缓存,占用系统内存,这样不合理.
应该使用图片的全路径数组,这样不会生成缓存,同时还应该在一个动画播放完毕后将其及时释放
*/
//UIImage *img = [UIImage imageNamed:imgName];
//图片资源放在Supporting Files
NSString *path = [[NSBundle mainBundle] 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. 在制作动画的时候,如果想设置其它属性注意要先设置好其它属性再开始动画,否则可能动画没有效果。