UI入门指引
1. iOS学习路线:
C语言:数据类型、流程控制、函数、指针、字符串、结构体、枚举、预处理;
OC:面向对象、内存管理、分类、协议、Block、KVC/KVO、Foundation框架;
iOS基础:
UIKit框架:基础视图:UIButton,UILabel,UITextField,UIImageView,UIScrollView等;
高级视图:UITableView,UIPickerView, IB的使用等
自定义视图;
控制器: UINavigationController, UITabBarController, 自定义视图控制器
触摸事件
手势
键盘处理
MVC模式、代理设计模式
通知机制
iOS高级:
数据存取:plist, 归档,SQLite等
多线程编程:GCD, NSOperationQueue, NSThread
网络:NSURLConnection,AFNetworking, CFNetworking
多媒体:音频、视频、相机、相册、流媒体
系统服务:推送、iCloud、内购、广告、蓝牙、打电话、发短信、通讯录,邮件
真机调试,发布
热门技术:二维码、加密、支付、XMPP即时通讯
2.iOS开发一般需要哪些内容
开发人员开发完应用程序后,需要把应用上传到App Store(苹果的应用商店),苹果审核后显示在商店中,用户从App Store中下载APP
3. UI
User Interface用户接口,用户通过UI和程序交互,提交请求,显示界面和结果。
可以这样理解,在iOS程序中,看得见的部分就是UI。类似于我们Mac机器的键盘、显示器、触摸板等
为了方便开发者开发出强大的功能,苹果提供了各种各样的框架
UIKit - 创建和管理应用程序的用户界面
QuartzCore -提供动画特效以及通过硬件进行渲染的能力
CoreGraphics -提供2D绘制的基于C的API
CoreLocation -使用GPS和WIFI获取位置信息
MapKit -为应用程序提供内嵌地图的接口
AVFoundation – 音频处理
4. UIKit框架
UIKit框架中提供了很多可视化的组件元素,我们利用UIKit框架提供的各种组件对象组合成美观的UI界面
需要提醒大家没必要一次性全部掌握所有控件的使用,也没必要掌握某个控件的所有用法。iOS控件的用法都是相似的,先掌握最主要、最常用的控件,其他控件用时再学
5. 分析界面中的控件
6. 第一个iOS程序
6.1 开发步骤
搭建UI界面,1个按钮,2个文本框,3个标签
监听按钮的点击事件
获取2个文本框的值,将最后结果显示出来
6.2 创建工程实现
7. Xcode布局
7.1 菜单栏
7.2 工具栏:启动、停止, 显示与隐藏边栏
7.3 导航区(Cmd+0):
Project Navigator(Cmd+1),管理当前工程的文件
Symbol Navigator,管理当前工程的类、属性和方法
Find Navigator,搜索
Issue Navigator, 问题导航
Test Navigator, 测试导航
Debug Navigator, 调试导航,会显示内存、CPU的占用情况
BreakPoint Navigator,显示所有断点,能够快速跳转到断点
Report Navigator, 日志导航,会显示当前项目的运行、调试等信息
7.4 编辑区
主要操作区域
7.5 实用工具区
7.5.1 对象相关属性区
选中某个对象后,在该区域显示当前对象的相关属性
7.5.2 库区
文件模板库,代码片段库,对象库和媒体库
7.6 调试区
一般分为变量区和控制台两个区域
8. 从main函数到AppDelegate
Supporting Files 中有main函数,在main函数中,仅仅是调用了UIApplicationMain函数.
UIApplicationMain 前两个参数为main函数的参数(可以通过edit Schema,设置main的参数);
第三个参数指定当前应用程序的类名,如果为nil,当前项目会创建一个UIApplication类的对象,也可以传递一个UIApplication子类,当前main函数就是根据第三个参数创建应用程序;一个UIApplication对象就代表一个应用程序;一个iOS程序启动后创建的第一个对象就是UIApplication对象;UIApplication对象是一个单例对象,可以通过[UIApplication sharedApplication]来获得当前应用程序;UIApplication的一个主要工作就是处理用户事件,它会是一个队列,对用户的操作逐个处理;UIApplication还维护一个在当前应用中打开的Window列表;UIApplication一般会被赋予一个代理对象(第4个参数),以处理应用程序生命周期事件,如程序的启动、关闭、进入后台、进入前台等。
第四个参数为当前应用程序的代理类,main函数根据当前代理类创建一个delegate对象,并将该delegate对象赋值给UIApplication对象的delegate属性。该代理类是一个遵从UIApplicationDelegate 应用程序代理协议的类,当应用发生一些系统级的事件时就会通知代理进行处理。如当来电或锁屏时会导致APP进入后台或终止,在APP受到类似干扰时,会产生一些系统事件,这时UIApplication会通知它的delegate对象,让代理来处理这些系统事件。
// 当应用程序启动完毕后系统会自动调用
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
// 当来电话或短信,或者用户退出应用程序时,应用从活动状态转入非活动状态时调用,在该方法中暂停正在执行的任务,使时钟无效,或暂停游戏
- (void)applicationWillResignActive:(UIApplication *)application {
}
// 当应用进入后台时调用,可以在该方法中保存用户数据,释放占用的资源,作废时钟,保存足够的程序状态以便应用重启时能够恢复到当前状态。需要注意的是当用户退出时,会调用这个方法,而不是applicationWillTerminate:方法
- (void)applicationDidEnterBackground:(UIApplication *)application {
}
// 当应用从后台即将变为前台时调用,一般在该方法中恢复应用进入后台时保存的状态
- (void)applicationWillEnterForeground:(UIApplication *)application {
}
// 当应用变为活动状态时调用,在该方法中启动在不活动状态中暂停的任务,如果应用之前已经进入后台,可能需要刷新用户界面
- (void)applicationDidBecomeActive:(UIApplication *)application {
}
// 当结束应用程序时调用该方法,如果合适可以保存数据,如果程序已经进入后台后,该方法不会再被调用。可以设置Info.plist文件,修改Application does not run in background属性设置为Yes后,程序将不再进入后台运行
- (void)applicationWillTerminate:(UIApplication *)application {
}
// 可选方法,当系统内存紧张时,尝试释放当前应用的一些内存,如果内存还不足,应用则终止
-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application{
}
9.程序的启动过程
在main函数中调用UIApplicationMain函数;
创建UIApplication对象,创建UIApplication的delegate对象;
开启一个事件循环(Main Runloop)监听系统级的事件;
如果没有storyboard故事板,程序启动完毕后就会调用AppDelegate中的- (BOOL)application: didFinishLaunchingWithOptions: 方法,在该方法中创建UIWindow对象,创建和设置UIWindow的rootViewController根视图控制器,显示窗口;参考代码:
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController *vc = [[ViewController alloc]init];
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];
如果有storyboard故事板的话,会根据Info.plist获得Main.storyboard,加载该故事板,创建UIWindow,设置UIWindow的rootViewController根视图控制器,显示窗口。
10 工程文件
AppDelegate.h和AppDelegate.m文件,应用的代理文件;
ViewController.h和ViewController.m文件,视图控制器,主要在视图控制器中编写逻辑代码;
Main.storyboard故事板,默认程序的启动界面,可以在该视图中添加控件,默认情况下,该视图的控制器为ViewController;默认启动Main.storyboard故事板,可以在Info.plist文件中重新设置主故事板的名称。在Main.storyboard中的View Controller(视图控制器)的左侧有一个箭头,表示该控制器是Initial View Controller。
Assets.xcassets是一个图片文件夹,用来存储项目图片,绿色文件夹表示真实存在的文件夹,黄色文件夹表示逻辑文件夹,便于在当前项目中管理相应的文件,不是真实存在的;
LaunchScreen.storyboard,是程序启动完成前的一个加载界面;
Info.plist是当前项目的相关信息;
Supporting Files逻辑文件夹,main函数在该文件夹中;
Products文件夹,保存生成的app
11 创建空工程
应用也可以不从Main.storyboard启动。可以删除掉Main.storyboard故事板,选中工程,在General选项卡中找到Main Interface列表框,删除Main。
打开AppDelegate.m文件,在文件顶部导入头文件
#import "ViewController.h”,
修改- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController *vc = [[ViewController alloc]init];
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];
return YES;
}
12. 设置控件的属性
12.1 直接在Attributes Inspector面板中设置
12.2在代码中设置
设置字体:lbl.font = [UIFont boldSystemFontOfSize:24];
NSLog(@"%@", [UIFont familyNames]);在控制台中输出支持的所有字体
设置文本颜色: lbl.textColor = [UIColor redColor];
设置文本的对齐方式: lbl.textAlignment = NSTextAlignmentRight;
字体自适应标签的宽度: lbl.adjustsFontSizeToFitWidth = YES; 需要注意的是不能自适应高度
UILabel的换行,先设置最多显示的行数: lbl.numberOfLines = 3;
如果文字不够,实际上是几行就是几行;如果行高不够,能显示几行就是几行;如果行数设置为0,表示没有行数限制。
然后设置换行中断模式:lbl.lineBreakMode = NSLineBreakByWordWrapping;
需要注意的是,在新版本的iOS中,ByWordWrapping、ByCharWrapping和ByClipping效果可能是一样的,显示不完全时,截断后面的字符;
设置tag标记,是一个正整数: lbl.tag = 123;可以通过tag标记快速访问控件如: (UILabel *) [self.view viewWithTag:123],
设置阴影的颜色和偏移: lbl.shadowColor = [UIColor yellowColor];
lbl.shadowOffset = CGSizeMake(2, 2);
设置透明度: lbl.alpha = 0.8;
13 现有iOS设备的坐标系
13.1 iPhone设备的大小
普通屏1点==1像素,Retina屏,1点==2像素,6+ ,1点==3像素
4s: 3.5寸, 320*480点, 640*960像素
5s: 4寸, 320*568点, 640*1136像素
6 : 4.7寸, 375*667点, 750*1334像素
6+: 5.5寸, 414*736点, 1242*2208像素,苹果会自动缩放到1080*2208像素
在准备APP所需要的图片时,需要准备三张相同的图,如:test.png(100*100)、test@2x.png(200*200)、test@3x.png(300*300),系统会根据当前设备自动选择相应的图片
13.2 frame和bounds
(1). frame 与 bounds的区别
-(CGRect)frame{
return CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height);
}
-(CGRect)bounds{
return CGRectMake(0,0, self.frame.size.width,self.frame.size.height);
}
bounds的原点是(0,0)点(就是view本身的坐标系统,默认永远都是0,0点),而frame的原点却是任意的(相对于父视图中的坐标位置)。
frame: 该view在父view坐标系统中的位置和大小。(参照点是父view的坐标系统)
bounds:该view在本地坐标系统中的位置和大小。(参照点是本地坐标系统,就相当于ViewB自己的坐标系统,以0,0点为起点)
center:该view的中心点在父view坐标系统中的位置和大小。(参照电是父视图的坐标系统)
每个view都有一个本地坐标系统。这个坐标系统作用比较重要,比如触摸的回调函数中的UITouch里面的>坐标值都是参照这个本地坐标系统的坐标。当然bounds这个属性也是参照这个本地坐标系统来的。其实本地坐标系统的关键就是要知道的它的原点(0,0)在什么位置(这个位置又是相对于上层的view的本地坐标系统而言的,当然最上面的一层view就是 window它的本地坐标系统原点就是屏幕的左上角了)。通过修改view的bounds属性可以修改本地坐标系统的原点位置。
例:
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 280, 250)];
[view1 setBounds:CGRectMake(-20, -20, 280, 250)];
//设置了bounds后,view1左上角的坐标相当于原点的位置是-20,-20
view1.backgroundColor = [UIColor redColor];
[self.view addSubview:view1];//添加到self.view
NSLog(@"view1 frame:%@========view1 bounds:%@",NSStringFromCGRect(view1.frame),NSStringFromCGRect(view1.bounds));
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
view2.backgroundColor = [UIColor yellowColor];
[view1 addSubview:view2];//添加到view1上,[此时view1坐标系左上角起点为(-20,-20)]
NSLog(@"view2 frame:%@========view2 bounds:%@",NSStringFromCGRect(view2.frame),NSStringFromCGRect(view2.bounds));
13.3 给控件重新设置大小及位置
CGRect newFrame = CGRectMake(100, 200, 200, 50);
lbl.frame = newFrame;
不能这样直接设置
lbl.frame.origin.x = 200; //error
14. UIButton
按钮,可以对应用的点击作出响应。继承自UIControl,间接继承自UIView。
14.1 通过鼠标从对象库中把按钮拖曳到视图中
14.2 通过代码添加
UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(100, 100, 100, 40)];
btn.backgroundColor = [UIColor cyanColor];
[btn setTitle:@"button" forState:UIControlStateNormal];
[btn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[self.view addSubview:btn];
上面代码实现了设置背景色、设置标题、设置标题颜色.
这儿用到一个状态,按钮常用 的状态包括正常状态、高亮状态、选中状态和禁用状态。如果没有设置高亮状态的标题,缺省和正常状态标题一样。
设置按钮的选中状态:btn.selected = YES;
设置禁用状态:btn.enabled = NO;
设置字体: btn.titleLabel.font = [UIFont boldSystemFontOfSize:28];
设置图片:[btn setImage:[UIImage imageNamed:@"navigationbar_arrow_up"] forState:UIControlStateNormal]; 如果图片较小,默认情况下图片在左侧,文字在右侧。
设置按钮的背景图片:[btn setBackgroundImage:[UIImage imageNamed:@"navigationbar_arrow_up"] forState:UIControlStateNormal];
14.3 系统默认样式按钮
UIButton *btn = [UIButton buttonWithType:UIButtonTypeContactAdd];
btn.frame = CGRectMake(100, 100, 200, 200);
btn.backgroundColor = [UIColor redColor];
btn.center = CGPointMake(100, 100);
现在很多系统样式按钮已经失效,不建议使用系统button
14.4 添加事件
14.4.1 在故事板中,通过鼠标拖曳添加动作
14.4.2 通过代码添加
[btn addTarget:self action:@selector(buttonClicked ) forControlEvents:UIControlEventTouchUpInside];
第一个参数是接收事件的对象;第二个参数是接收到事件后需要进行的动作;第三个参数是接收什么类型的事件。当运行APP后,单击这个按钮,就会触发UIControlEventTouchUpInside事件,系统收到该事件后,就会交给当前对象self(ViewController视图控制器)响应这个事件,然后会跳转到buttonClicked方法中执行。
在ViewDidLoad方法的下面添加一个方法:
-(void)buttonClicked{
self.view.backgroundColor = [UIColor lightGrayColor];
}
14.4.3 带参数的事件响应程序
(1). 添加动作时,可以指定参数,一般是当前按钮本身
(2). 在添加事件时,可以在响应消息后添加一个冒号,如:
[btn addTarget:self action:@selector(buttonClicked: ) forControlEvents:UIControlEventTouchUpInside];
相应的响应方法修改为:
- (void)buttonClicked:(UIButton *)button{
self.view.backgroundColor = [UIColor lightGrayColor];
// 在方法中可以通过button来访问当前响应事件的按钮
[button setTitle:@"被点了" forState:UIControlStateNormal];
}
15. 时钟NSTimer
15.1 创建NSTimer对象
Timer可以等待一定的时间间隔,然后给目标对象发送一条指定的消息。如创建一个时钟对象,给window发送一条消息,告诉window在指定间隔后更新。
NSTimer和run loops运行循环一起工作。
/**
* 创建一个时钟对象,该对象会立即加入到运行循环中
*
* 第一个参数是时间间隔
* 第二个参数响应对象
* 第三个参数是响应方法
* 第四个参数是传递用户信息
* 第五个参数是否允许每隔指定的时间间隔就发送一次消息
*
* @return 返回一个时钟对象
*/
NSTimer _timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(moveLabel) userInfo:nil repeats:YES];
也可以先创建时钟,再手动把时钟添加到运行循环中,如:
NSTimer _timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(moveLabel) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
15.2 实例
(1). 创建一个SingleView Application
(2). 在ViewController的类扩展中添加一个NSTimer成员变量
@interface ViewController (){
NSTimer *_timer; // 声明一个成员变量
}
@end
(3). 在viewDidLoad方法中,创建一个按钮,创建一个标签,初始化NSTimer成员变量
- (void)viewDidLoad {
[super viewDidLoad];
// 创建一个按钮
[self createButton];
// 创建一个标签
[self createLabel];
// _timer成员变量初始化
_timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(moveLabel) userInfo:nil repeats:YES];
}
(4). 编写代码创建一个按钮
- (void)createButton{
UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(50, 50, 200, 30)];
btn.backgroundColor = [UIColor redColor];
[btn setTitle: @"点我启动或停止" forState:UIControlStateNormal];
[btn addTarget:self action: @selector(startOrStop) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
编写代码,完善点击按钮的响应程序
- (void)startOrStop{
static BOOL isRunning = YES;
if (isRunning ) {
[_timer setFireDate:[NSDate distantFuture]];
isRunning = NO;
}else{
[_timer setFireDate:[NSDate distantPast]];
isRunning = YES;
}
}
(5). 创建一个标签
- (void)createLabel{
UILabel *lbl = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 50, 30)];
lbl.backgroundColor = [UIColor redColor];
lbl.textColor = [UIColor blueColor];
lbl.text = @"我是标签";
lbl.tag = 123;
[self.view addSubview:lbl];
}
(6). 编写代码,完善定时器的响应方法
- (void)moveLabel{
static int xOffset = 5, yOffset = 5 ;
UILabel *lbl = (UILabel *) [self.view viewWithTag:123];
CGRect frame = lbl.frame;
frame.origin.x += xOffset;
frame.origin.y += yOffset;
CGFloat width = self.view.bounds.size.width;
CGFloat height = self.view.bounds.size.height;
if (frame.origin.x >= width || frame.origin.x < 0) {
xOffset *= -1;
}
if (frame.origin.y >= height || frame.origin.y < 0 ) {
yOffset *= -1;
}
lbl.frame = frame;
}
【注】实践是检验真理的唯一标准!最好应用纯代码敲一遍