#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中

  • 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

  1. 界面的切换涉及到UIView的创建和销毁
  2. 涉及UIView跟用户交互
  3. 显示一个新界面之前, 先创建了一个UIViewControler对象,然后创建一个UIView界面, UIViewControler管理UIView, 负责UIView创建, 销毁, 显示, 监听, 与用户的交互

@property(nonatomic,retain) UIView *view;

##1.5. 运行流程

  1. 读取Main.storyboard文件
  2. 创建箭头所指的MJViewController对象
  3. 根据storyboard文件中描述创建ViewController的UIView对象
  4. 将UIView对象显示到用户眼前

#2. 按钮的基本使用

  1. 按钮可以显示文字, 可以显示图片,可以随时调整内部图片和文字
  2. UIButton的状态
  • normal : 普通状态
  • highlighted : 长按按钮的状态(type修改为custom)
  • disabled
  1. 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
- (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
//退出键盘
[self.view endEditing:YES];

##2.4. 从资源文件中获取数据

1
2
3
4
5
6
7
8
9
//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
//重构, 相同的代码放到函数中, 不同的东西变为代码
- (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

  1. 如果仅仅是显示图片不需要监听, 则使用BUImageView
  2. 既要显示图片又要监听图片点击, 用UIButton

相同点
: 都能显示图片

不同点
: 1. UIButton能处理点击事件, UIImageView不能处理点击事件; UIButton能显示图片又能显示文; UIButton能同时显示两张图

UIButton继承自UIControl, 因此默认就能处理事件
UIImageView继承自UIView, 因此默认就不能处理事件

#3. 数据类型
字典
: 设置数据和取出数据使用字符串类型的key, 编写这些key时, 编译器不会有警告, 容易敲错

模型
: 数据模型,专门用来存放数据的对象, 设置数据和取出数据都是通过它的属性, 编译器会报错, 保证了数据的正确性,推荐使用

copy : NSString
strong : 一般对象
weak : UI控件
assign : 基本数据类型

模型

##3.1. instancetype

  1. 在类型表示上, 和id一样, 可以表示任何对象类型
  2. 只能用在返回值类型上
  3. 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
- (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, 把内部子控件的创建屏蔽起来

  1. 新建一个继承UIView的自定义View, 假设类名为AppView
  2. 新建一个AppView.Xib(建议Xid的名称和新建类相同),用来描述AppView的内部结构(AppView *appView = [[AppView alloc] init]; appView.frame = CGRectMake(x, x, x, x); …; [appView addSubview:imageView]; return @[appView, ..); 最终返回控件数组)
  3. 修改UIView的类型为AppView真实类型
  4. 将内部子空间与AppView进行属性连线
  5. AppView提供一个模型属性, 重写模型的set方法, 因为在set方法中可以拿到外界传递的模型数据
  6. 把模型数据拆开, 分别设置数据到对应的子控件中.
  7. 补充: 提供一个创建AppView的雷芳, 将读取Xib的代码屏蔽起来

##3.4. MVC
Model(数据模型) View(视图) Control(控制器)

#4. UIScrollView

内容超出屏幕的显示范围, 需要使用UIScrollView

  1. 将需要演示的内容加入UIScrollView
  2. 设置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;
是否显示垂直滚动条

size

##4.2. UIScrollView的代理(delegate)

代理相当于监听器

按钮点击时间使用addTarget

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

delegation
vie

代理设计的用途 :

  1. 监听思想(一个对象听见另一个对象的状态)
  2. 通知思想(一个对象状态改变, 想通知另一个对象)

当用户在UIScrollView身上使用捏合手势时,UIScrollView会调用代理的viewForZoomingInScrollView:方法,这个方法返回的控件就是需要进行缩放的控件