学习目标
1.【理解】代码创建控件过程
2.【理解】代码实现QQ登陆界面
3.【理解】图片浏览器
4.【理解】汤姆猫小游戏
一、代码创建控件过程
所有控件都是类的对象,不同的类创建可以不同类型的控件。也是就说创建一个控件其实就是创建一个对应类的对象。
常用控件类型
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设置文本,那和以系统不知道这个文本是那一种状态下显示的文本,干脆不显示。
二、代码实现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中学习的创建对象、调用方法是没有任何区别的。
三、图片浏览器
这个案例的主要目的是熟悉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]];
四、帧动画之汤姆猫
这个案例的主要目的是了解什么是帧动画,同时掌握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. 在制作动画的时候,如果想设置其它属性注意要先设置好其它属性再开始动画,否则可能动画没有效果。