Feb 3

【Lrdcq的iOS入门 DAY1】快速上手写界面

Lrdcq , 2016/02/03 18:33 , 教程 , 閱讀(4101) , Via 本站原創
Attention:本教程,不,其实是我学习review笔记,主要目的是我自己将我近一个月以来学习ios的姿势与方式用循序渐进的方式重新整理与归纳,并总结为阶梯性的知识点。教程意义不大,多半是给自己看的,所以看到我胡扯乱弹琴或者老是忘事儿请不要太在意。
本教程所有第0章节都是废话,有基础者可以跳过的,请务必注意。


新建一个ios项目 - helloWorld - 抛弃xib,成为手写界面党 - 用pod加载拓展 - 自动布局



step0.新建一个ios项目

首先,咋们使用的工具是传统的xcode,虽然作为ide它并不是最强大的,但用它来开发ios确实非常舒适,sdk模拟器开发环境之类的都为一键配置完成了,所以我们还是选择它。

那么,我们新建一个ios的single view application项目,这就是我们的起点了。

进去项目,xcode事先为我们预备好了很多文件包括:

  - AppDelegate.h/m 这可以理解为app类,以整个app维度的操作均在这个类中完成。(类似于安卓中的application类)
  - ViewController.h/m 一个起始的viewcontroller,即一个界面。(类似于安卓中的activity类)
  - Main.storyboard 一个storyboard,它的前身是xib,均是由xml构成的界面定义,xcode提供了非常高大上的编辑界面。(类似于安卓中的xml布局文件,但由于涉及到界面与代码交互,所以远比安卓的布局文件复杂)
  - LaunchScreen.storyboard 作为launch屏的样式。
  - main.m 和普通的c语言程序一样,是程序实际的入口咯。
  - 还有其他的文件包括资源文件和项目配置等,就此打住。

这些文件之间的关系是:从main中开启AppDelegate,之后通过配置文件的信息默默的加载ViewController并调用Main.storyboard的界面应用于ViewController的view中。点击左上角的run就可以看到效果辣~当然现在什么也没有。

step1.helloWorld

刚才起始的程序是一片空白,什么也没有,所以,我们加上一句“helloworld”吧。

进入ViewController.m,系统实现为我们准备了两个坑,我们看到重写的方法- (void)viewDidLoad,它的注释是Do any additional setup after loading the view,哦对,我们事实上要在vc从xib加载完节目之后在它上面写一行字,那就在这里咯。(常把这个方法看作安卓中的onCreate用)

静态文本的控件是UILabel,所以我们在方法体中加入如下代码:
UILabel *text = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 30)];
text.text = @"HelloWorld";
[self.view addSubview:text];

然后直接run出来,我们看到在界面的左上角,真真切切的被状态栏挡住的左上角下,出现了我们想要的文字....虽然位置并不是那么舒服。问题出在我们设置的Frame,让我们来计算一个全屏居中的frame吧,计算过程大概这样,顺便把addSubview的形式改得舒服了一点,再顺便调整了一下UILabel的样式,于是代码变成这样了:
[self.view addSubview:({
    UILabel *text = [[UILabel alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2-50, self.view.frame.size.height/2-25, 100, 50)];
    text.text = @"HelloWorld\nI love U";
    text.textAlignment = NSTextAlignmentCenter;
    text.numberOfLines = 0;
    text.textColor = [UIColor blueColor];
    text;
})];

一行蓝色的全屏居中的“helloworld I love U”终于出现在的屏幕上,bingo!

step2.抛弃xib,成为手写界面党

写了这么久,我们意识到一个问题,我们虽然用代码在界面上添加控件,但下面还是加载了我们的默认的storyboard或者说xib的。而我们,打算摒弃xib。为何要摒弃xib呢?

  - 很大一个原因是xib/storyboard过于复杂。安卓的xml布局文件只是包含了界面布局的定义与控件样式的定义,稍复杂的页面也是轻轻松松好几百行了,而ios的xib除了描述样式与布局,还包括与viewcontroller的绑定关系,各个控件操作与响应之间的绑定关系(安卓其实也有这样的功能,但一般认为那是ugly code),如果是storyboard的话还有界面之间的跳转关系。简而言之,这个文件需要写入的东西太多了,根本不适合手写,而xcode提供的图形化操作界面也并不是那么顺手(另外大多数同学天生反感深度图形化操作界面)。
  - 另外,在当个文件中代码量过大,信息量过多,在团队开发的过程中多个开发者操作同一个文件的后果,可想而知,一旦遇到冲突,解决起来简直生不如死。
  - 再者,由于一般用图形界面操作xib文件,很多代码上的细节其实我们并不清楚,就算对应着xml源代码看也是那样。这很不利于我们对界面的优化与微调,老是出这样那样的错误。

原因很明显了,那我们要下刀把项目中的Main.storyboard给砍掉。那我们先删除掉它吧,然后点击项目,修改General下的Deployment Info下的Main InterFace,这里面本来可选一个storyboard,现在清空里边即可。此时我们再编译进入app,好的,现在已经啥也没有了,那么我们怎么选择我们的viewcontroller加载出来呢?在AppDelegate的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法中,新建窗口并载入我们的第一个viewcontroller类:
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
ViewController *vc = [[ViewController alloc] init];
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];

用主屏的大小初始化app的window,并且把window的根ViewController设为我们自己的viewcontroller的实例再刷新,就ok辣。现在,我们就可以基本上完全抛弃布局文件,只通过viewcontroller中的代码绘制我们的界面了。

在初始化ViewController,我们可以看到有初始化方法initWithNibName:<#(nullable NSString *)#> bundle:<#(nullable NSBundle *)#>,这就是从布局文件价值的方法了。

step3.用pod加载拓展

在正式开展工作之前,我们还有一件不得不做的工作,就是安装拓展(轮子)。说好了一般来说不重复发明轮子,我们的项目中必然会引入很多第三方库。

说到引入第三方库,每一种平台/语言都有自己的官方/非官方工具。比如很多脚本语言都有xpm工具即x语言package manager,安卓项目,即java项目中我们使用gradle来使用第三方库,而ios开发呢?苹果官方并没有给出官方的解决方案,因此有第三方的开发者解决了,这就是工具:CocoaPods,cocoa代码库管理工具。pod的本质是基于ruby的一个第三方代码,我们通过ruby官方的RubyGems(ruby package manager)来安装pod(或者使用苹果下常用的三方库管理工具brew来安装)。

在控制台输入命令pod,如果出现了对应的提示信息,就可以进行下一步了:编写依赖第三方库配置文件。在项目目录下新建一个纯文本文件:Podfile,并在里边输入类似于这样的内容:
source 'https://github.com/CocoaPods/Specs.git'

platform :ios, ‘9.0’

pod "Masonry", "0.6.3"
pod "ReactiveCocoa", "2.5
pod "AFNetworking", "2.5.4"

显然,分别设置了仓库源,应用到的平台与版本,和具体安装了些啥库与版本信息。当然可以配置的东西远比这个复杂,不过这样就可以简单的把Masonry,ReactiveCocoa,AFNetworking三个库引入我们的项目中了。编写好这个文件,我们在终端进入项目目录,运行pod install,pod就会读取这个配置文件然后进行一堆又一堆下载与复杂的配置操作,然后就把这堆东西真正引入项目中了。当然,其实pod为我们项目架设在一个工作区中,以后启动项目的时候就别从.xcodeproj的项目文件启动啦,从.xcworkspace的工作区文件启动吧。
使用教程:http://blog.devtang.com/blog/2014/05/25/use-cocoapod-to-manage-ios-lib-dependency/

每次项目编译的时候,pod都会检查podfile.lock与项目原有的备份文件内容是否一致,如果不一致的话会抛出错误,在pod文件更新后请及时重新pod install。另外pod生成的文件与文件夹到底是否要储存到版本管理,怎样储存到版本管理也是一件有争议的事儿。

step4.自动布局

回到我们的helloworld上。我们的代码有一段看起来很烦人的东西,那就是计算frame来实现剧中那一端,CGRectMake(self.view.frame.size.width/2-50, self.view.frame.size.height/2-25, 100, 50),要多恶心有多恶心,试想如果界面中多个控件相互依赖对齐,那对frame的计算岂不是超级复杂。嗯,因此在ios后来的版本中,苹果引入了一个叫自动布局(autolayout)的技术来帮助我们做这个事儿。autolayout主要是针对xib布局文件上的,在布局文件上配置布局中的对齐,紧靠之类的自动布局属性就很轻松了。

然而,我们上上一步才表明了太度,不使用布局文件,用手写代码来绘制界面,再看看自动布局的代码api....那就超级恶心了。那我们应该怎么做呢?我们引入了第三方库Masonry,来帮我们简化自动布局api,让我们轻松的设置一个控件的布局。

说到自动布局,就不得不提到一个词“约束”了,一个控件的frame是定义的控件的位置(position)和大小(size)的,一些条件可以决定一个控件的位置和大小,就是一组约束,一组足以完全定义控件位置和大小的约束才是一个稳定的约束,控件才能够显示在界面上,同时如果界面中有控件的约束不足,那这个界面就无法呈现出来,当然也会抛出错误了。

用Masonry设置一个控件的约束简直是再简单不过。比如设置如上uilabel居中,可以这样:
[label mas_makeConstraints:^(MASConstraintMaker *make) {
    make.center.equalTo(self.view);
    make.width.equalTo(@100);
    make.height.equalTo(@50);
}];

我们定义了它的中心和self.view一样,那位置确定了,然后定义了长宽的具体数值,那大小确定了,这是一组完整的约束,那就完成了。那说好的自动布局呢?此时假设我们有label2,那自动布局的优势就出来了。看如下约束:
[label2 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.centerX.equalTo(label).offset(50);
    make.centerY.equalTo(self.view);
    make.width.equalTo(label);
    make.height.equalTo(label);
}];

用文字描述这段约束,label2的x轴中心和label相等然后错位50。y轴中心还是和父级view相等,而label2的大小和label完全一样。嗯确实可以定义label2的布局了,而且是和label相关的。这就是自动布局。

Masonry除了,为控件添加了mas_makeConstraints,mas_remakeConstraints这种方法来设置约束,也添加了很多mas开头的属性来方便进行约束设置,比如:
[label2 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(label.mas_bottom);
    make.centerX.equalTo(self.view.mas_centerXWithinMargins);
    make.width.equalTo(label.mas_width);
    make.height.equalTo(label.mas_height);
}];

这个约束定义的是啥可以直接“望文生义”,它的顶部位置和label的底部相等,它的x轴位置与view的margin内中心相等,高宽分别等于label的高宽。it is done。

顺带一提有部分控件是有默认大小计算方式的,比如uilabel如果只设置了宽约束而没设置高约束的话,label会根据文本的内容自动排布并计算最小高度。有固定样式的控件,比如switch之类的控件也会吐出它的默认高宽,自动布局在约束不足的情况下会根据这个数儿进行布局,而不会直接抛错。

自动布局更多的信息请参看http://zhangbuhuai.com/2015/07/16/beginning-auto-layout-part-1/,Masonry库快速上手教程:http://adad184.com/2014/09/28/use-masonry-to-quick-solve-autolayout/

掌握Masonry编写约束后,我们就基本可以使用代码随心所欲的手写界面,程序界面部分当然也可以轻松拿下。
logo