#1. 开发概览
SDK(Software Develop Kit)
IBAction(相当于void) IBOutlet 用于联系
安装非8.0 sdk 将文件夹拖入/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs下
添加离线文档文档. 将解压后的文件拖入/Applications/Xcode.app/Contents/Developer/Documentation/DocSets中,(在完全退出Xcode下)
查看User EXperience
##1.1. 初识UI
- UI是app的基础, 然后在UI的基础上增加实用功能, 开发中绝大多数时间在处理UI
万物皆对象, UI界面由对象组成, 将对象显示到屏幕上
- 主要在UIKit框架提供了很多可视化组件元素
##1.2. 常用框架
- UIKit(创建和管理应用程序的用户界面)
- QuartzCore(提供动画特效以及通过硬件进行渲染的能力)
- CoreGraphics(提供2D绘制的基于C的API)
- CoreLocation(使用GPS和WIFI获取位置信息)
- MapKit(为应用程序提供内嵌地图的接口)
- AVFoundation(音频处理)
##1.3. UIView
- 屏幕上看得见摸得到的东西就是UIView, 一般翻译为
视图/控件/组件
- 按钮,文字,图片的UI都是继承自UIView
- UIView是一个容器, 容纳其他UIView
- 理解父控件/子空间
每一个UI控件都有自己的独特属性,但是有些属性是每个UI控件都具备的,比如每一个UI控件都有自己的位置和尺寸、都有自己的父控件、子控件。于是,所有的UI控件最终都继承自UIView,UI控件的公共属性都定义在UIView中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @property(nonatomic,readonly) UIView *superview; 获得自己的父控件对象
@property(nonatomic,readonly,copy) NSArray *subviews; 获得自己的所有子控件对象
@property(nonatomic) NSInteger tag; 控件的ID\标识,父控件可以通过tag来找到对应的子控件
@property(nonatomic) CGAffineTransform transform; 控件的形变属性(可以设置旋转角度、比例缩放、平移等属性)
@property(nonatomic) CGRect frame; 控件所在矩形框在**父控件**中的位置和尺寸(以父控件的左上角为坐标原点)
@property(nonatomic) CGRect bounds; 控件所在矩形框的位置和尺寸(以自己左上角为坐标原点,所以bounds的x\y一般为0)
@property(nonatomic) CGPoint center; 控件中点的位置(以父控件的左上角为坐标原点)
|
##1.4. UIViewControler
- 界面的切换涉及到UIView的创建和销毁
- 涉及UIView跟用户交互
- 显示一个新界面之前, 先创建了一个
UIViewControler对象,然后创建一个UIView界面, UIViewControler管理UIView, 负责UIView创建, 销毁, 显示, 监听, 与用户的交互
@property(nonatomic,retain) UIView *view;
##1.5. 运行流程
- 读取Main.storyboard文件
- 创建箭头所指的MJViewController对象
- 根据storyboard文件中描述创建ViewController的UIView对象
- 将UIView对象显示到用户眼前
#2. 按钮的基本使用
- 按钮可以显示文字, 可以显示图片,可以随时调整内部图片和文字
- UIButton的状态
- normal : 普通状态
- highlighted : 长按按钮的状态(type修改为custom)
- disabled
- autolayout(自动布局): 修改button要取消自动布局
1 2 3 4
| frame : 能修改尺寸和位置 center : 能修改位置 bounds : 能修改尺寸(x, y一般都是0) transform : 可以修改尺寸/旋转角度/位置
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| - (IBAction)uptransform { //1. 取得头像按钮(用tag的方法) 将父类self.view强制转换成子类类型 UIButton *head = (UIButton *)[self.view viewWithTag:10]; //会递归查找tag为10的按钮,view->子控件->孙子控件 //2.用transform平移, tx ty是告诉系统要偏移多少 //transform是在初始位置的基础上平移,所以需要每次都对ty -50 //head.transform = CGAffineTransformMakeTranslation(0, 50); //在传入的tranform是在传入的基础transform上平移 head.transform = CGAffineTransformTranslate(head.transform, 0, 50); //3. transform左旋转 //角度为正数,是顺时针, 传入角度制 PI/4 head.transform = CGAffineTransformRotate(head.transform, M_PI_4); //4. 缩放 ,放大1.2倍, 缩小0.8倍 head.transform = CGAffineTransformScale(head.transform, 1.2, 1.2); }
|
##2.1. 自动生成按钮
凡是storyboard有的功能都能用代码解决
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| //控制器的view加载完毕的时候调用 //一般在这里进行界面的加载 - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //创建控件 UIButton *button = [[UIButton alloc] init]; //添加按钮 [self.view addSubview:button]; //设置尺寸 button.frame = CGRectMake(100, 100, 100, 100); //设置颜色 button.backgroundColor = [UIColor redColor]; }
|
##2.2. Xcode的快捷键
- Option + cmd + 回车 打开辅助视图(分栏)
- cmd + 0 打开或者取消左边的导航栏
- option + cmd 0 打开或者取消右边的属性视图
- cmd + r 运行
- cmd + . 停止运行
- Shift + cmd + h 模拟测试回到首页(相当于home)
- 两次Shift + cmd + h 打开模拟测试的任务管理器
##2.3. 退出键盘
1 2 3
| //退出键盘 [self.view endEditing:YES];
|
##2.4. 从资源文件中获取数据
1 2 3 4 5 6 7 8 9 10
| //File是全路径, 应该是手机上的全路径 //一个NSbundle代表一个文件夹 //利用mainBundle可以访问手机里的任何资源 NSBundle *bundle = [NSBundle mainBundle];
//第一个参数名为文件名 第二个参数为后缀, 这个函数用于获取全路径
NSString *path = [bundle pathForResource:@"imageData" ofType:@"plist"]; _imageData = [NSArray arrayWithContentsOfFile:path];
|
##2.5. 序列帧动画
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
| //重构, 相同的代码放到函数中, 不同的东西变为代码 - (void)runAnimationCount : (int)count name : (NSString *)name { //如果有其他动画在播放则不给出反应 if (self.tom.isAnimating) { return; } //1. 加载所有图片的动态数组 NSMutableArray *images = [NSMutableArray array]; for (int i = 0; i < count + 1; ++i) { //计算文件名 NSString *filename = [NSString stringWithFormat:@"%@_%02d.jpg", name, i]; //加载图片, // imageNamed方法使用缓存机制, 不会释放加载的图片, 大量图片不能使用这个方法 //UIImage *image = [UIImage imageNamed:filename]; //传入全路径, 且没有缓存 NSBundle *bundle = [NSBundle mainBundle]; NSString *path = [bundle pathForResource:filename ofType:nil]; UIImage *image = [UIImage imageWithContentsOfFile:path]; //将UIImage对象放到动态数组中 [images addObject:image]; } //将动态数组赋值给动画数组 self.tom.animationImages = images; //2. 设置播放次数 self.tom.animationRepeatCount = 1; //3. 设置播放次数 self.tom.animationDuration = images.count * 0.1; [self.tom startAnimating]; //定时器 CGFloat delay = self.tom.animationDuration + 1.0; [self.tom performSelector:@selector(setAnimationImages:) withObject:nil afterDelay:delay]; //[self performSelector:@selector(clearCache) withObject:nil afterDelay:delay]; }
|
##2.6. 文档注释
/** 这个一个文档注释 */
##2.7. UIImageView和UIButton
- 如果仅仅是显示图片不需要监听, 则使用BUImageView
- 既要显示图片又要监听图片点击, 用UIButton
- 相同点
- 都能显示图片
- 不同点
- 1. UIButton能处理点击事件, UIImageView不能处理点击事件; UIButton能显示图片又能显示文; UIButton能同时显示两张图
UIButton继承自UIControl, 因此默认就能处理事件
UIImageView继承自UIView, 因此默认就不能处理事件
- #3. 数据类型
字典 - 设置数据和取出数据使用
字符串类型的key, 编写这些key时, 编译器不会有警告, 容易敲错
- 模型
- 数据模型,专门用来存放数据的对象, 设置数据和取出数据都是通过它的属性, 编译器会报错, 保证了数据的正确性,
推荐使用
copy : NSString
strong : 一般对象
weak : UI控件
assign : 基本数据类型

##3.1. instancetype
- 在类型表示上, 和
id一样, 可以表示任何对象类型
- 只能用在返回值类型上
- 比
id多一个好处 : 编译器会检测instancetype的真实类型
##3.2. Xib使用
storyboard文件软件界面, 整个软件所有界面(重量级)
Xib描述软件界面(轻量级)
- 两者都使用Interface Builder工具来编辑(就是Xcode的界面)
- 加载Xib有两种:
NSArray *objs = [bundle loadNibNamed:@”AppView” owner:nil options:nil];
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
| - (void)viewDidLoad { [super viewDidLoad]; //添加应用信息, //应用尺寸, 宽度高度 int totalColumns = 3; CGFloat appW = 85; CGFloat appH = 90; //计算view之间的间隙 = (屏幕宽度self.view - 3 * 应用的宽度view) / 4 CGFloat marginX = (self.view.frame.size.width - 3 * 85) / 4; CGFloat marginY = 35; for (int index = 0; index < self.apps.count; index++) { //1. 创建view NSBundle *bundle = [NSBundle mainBundle]; //读取Xid文件, 会创建Xid中的所有对象, 并且按顺序放到数组中返回 NSArray *objs = [bundle loadNibNamed:@"AppView" owner:nil options:nil]; UIView *appView = [objs lastObject]; //2. 添加view [self.view addSubview:appView]; //3. 设置frame, 计算x y int row = index / totalColumns; int col = index % totalColumns; CGFloat appX = marginX + (appW + marginX) * col; CGFloat appY = marginY + (appH + marginY) * row; appView.frame = CGRectMake(appX, appY, appW, appH); //4. 设置数据 图片 名称 appView上三个子控件 AppModel *app = self.apps[index]; //UIImageView *iconView = appView.subviews[0]; UIImageView *iconView = (UIImageView *)[appView viewWithTag:10]; iconView.image = [UIImage imageNamed:app.icon]; //UILabel *nameLbale = appView.subviews[1]; UILabel *nameLabel = (UILabel *)[appView viewWithTag:20]; nameLabel.text = app.name; /* //1. 创建子view UIView *appView = [[UIView alloc] init]; //设置背景色 //appView.backgroundColor = [UIColor redColor]; //2. 计算应用相对于父控件的坐标, 应该知道行号和列号, 列号应该是index mod(3) ,行号为序号 / 3 //总列数 int totalColumns = 3; int row = index / totalColumns; int col = index % totalColumns; CGFloat appX = marginX + (appW + marginX) * col; CGFloat appY = marginY + (appH + marginY) * row; //3. 添加子view到父控件上 appView.frame = CGRectMake(appX, appY, appH, appW); [self.view addSubview:appView]; AppModel *appInfo = self.apps[index]; //4. 添加内部小控件 图片 名字 和下载按钮 UIImageView *iconView = [[UIImageView alloc] init]; CGFloat iconW = 45; CGFloat iconH = 45; CGFloat iconX = (appW - iconW) * 0.5; CGFloat iconY = 0; iconView.frame = CGRectMake(iconX, iconY, iconW, iconH); //iconView.backgroundColor = [UIColor blueColor]; iconView.image = [UIImage imageNamed:appInfo.icon]; [appView addSubview:iconView]; UILabel *nameLabel = [[UILabel alloc] init]; CGFloat nameW = appW; CGFloat nameH = 20; CGFloat nameX = 0; CGFloat nameY = iconY + iconH; nameLabel.frame = CGRectMake(nameX, nameY, nameW, nameH); //nameLabel.backgroundColor = [UIColor blueColor]; nameLabel.text = appInfo.name; //设置字体大小 nameLabel.font = [UIFont systemFontOfSize:13]; nameLabel.textAlignment = NSTextAlignmentCenter; [appView addSubview:nameLabel];
UIButton *downBtn= [[UIButton alloc] init]; CGFloat btnX = 10; CGFloat btnY = nameY + nameH; CGFloat btnW = appW - 2 * btnX; CGFloat btnH = 20; downBtn.frame = CGRectMake(btnX, btnY, btnW, btnH); //downBtn.backgroundColor = [UIColor blueColor]; [downBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal]; [downBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateHighlighted]; [downBtn setTitle:@"点击下载" forState:UIControlStateNormal]; //按钮设置字体属性 downBtn.titleLabel.font = [UIFont systemFontOfSize:13]; //按钮内部有label和image [appView addSubview:downBtn]; */
} }
|
##3.3. Xib的封装步骤
如果View内部的子控件太多, 一般考虑自定义View, 把内部子控件的创建屏蔽起来
- 新建一个继承UIView的自定义View, 假设类名为AppView
- 新建一个AppView.Xib(建议Xid的名称和新建类相同),用来描述AppView的内部结构(AppView *appView = [[AppView alloc] init]; appView.frame = CGRectMake(x, x, x, x); …; [appView addSubview:imageView]; return @[appView, ..); 最终返回控件数组)
- 修改UIView的类型为AppView真实类型
- 将内部子空间与AppView进行属性连线
- AppView提供一个模型属性, 重写模型的set方法, 因为在set方法中可以拿到外界传递的模型数据
- 把模型数据拆开, 分别设置数据到对应的子控件中.
- 补充: 提供一个创建AppView的雷芳, 将读取Xib的代码屏蔽起来
##3.4. MVC
Model(数据模型) View(视图) Control(控制器)
#4. UIScrollView
内容超出屏幕的显示范围, 需要使用UIScrollView
- 将需要演示的内容加入
UIScrollView
- 设置UIScrollView的contentSize属性, 告诉UIScrollView所有内容尺寸
1 2 3 4 5 6
| UIScrollView无法滚动的原因 1. 没有设置contentSize 2. scrollEnabled = NO 3. 没有接收到触摸事件 : userInteractionEnabled = NO 4. 没有取消autolayout功能 等
|
##4.1. UIScrollView重要属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @property(nonatomic) CGPoint contentOffset; 这个属性用来表示UIScrollView滚动的位置(滚动时, 图片的左上角和屏幕左上角之间的相对位置坐标)
@property(nonatomic) CGSize contentSize; 这个属性用来表示UIScrollView内容的尺寸,滚动范围(能滚多远) frame.size表示可视范围(在屏幕上显示的范围), contentSize整个滚动的区域范围
@property(nonatomic) UIEdgeInsets contentInset; 这个属性能够在UIScrollView的4周增加额外的滚动区域
//其他常用属性 @property(nonatomic) BOOL bounces; 设置UIScrollView是否需要弹簧效果
@property(nonatomic,getter=isScrollEnabled) BOOL scrollEnabled; 设置UIScrollView是否能滚动
@property(nonatomic) BOOL showsHorizontalScrollIndicator; 是否显示水平滚动条
@property(nonatomic) BOOL showsVerticalScrollIndicator; 是否显示垂直滚动条
|

##4.2. UIScrollView的代理(delegate)
代理相当于监听器
按钮点击时间使用addTarget
- 很多时候,我们想在UIScrollView正在滚动 或 滚动到某个位置 或者 停止滚动 时做一些特定的操作
- 要想完成上述功能,前提条件就是能够监听到UIScrollView的整个滚动过程
- 当UIScrollView发生一系列的滚动操作时, 会
自动通知它的代理(delegate)对象,给它的代理发送相应的消息,让代理得知它的滚动情况


代理设计的用途 :
- 监听思想(一个对象听见另一个对象的状态)
- 通知思想(一个对象状态改变, 想通知另一个对象)
当用户在UIScrollView身上使用捏合手势时,UIScrollView会调用代理的viewForZoomingInScrollView:方法,这个方法返回的控件就是需要进行缩放的控件