iOS开发-视图控制器相关

本文详细介绍了iOS中视图控制器的生命周期,从alloc到viewDidDisappear的各个阶段,并深入探讨了视图加载、屏幕适配及自定义视图等关键环节。此外,还讨论了APP启动原理、状态栏和导航栏的特性及其对视图的影响。
摘要由CSDN通过智能技术生成

视图控制器生命周期

alloc

创建控制器,分配内存地址

init

初始化控制器。

loadView

加载视图。控制器被创建以后,其view并没有随之创建(即self.view是为nil),而是在该方法中创建view,将其赋值给self.view。若是nib文件,则加载nib中的view(包括子视图);若是纯代码,则自动创建一个view。

viewDidLoad

视图加载完毕。可以在这里对视图做自定义的更改。需要注意的是在该方法中视图(self.view)还没有进行屏幕适配,也就是说,如果是从nib中加载的,nib中的view多大,self.view.frame就多大;如果是纯代码加载的控制器,frame默认是(320,568)。因此在这个方法中自定义视图如果要借助view.frame就要格外小心了。

viewWillAppear

视图即将显示到屏幕。view会在这里去适应屏幕的大小,因此view
.frame会更新。frame更新会调用view的layoutSubViews方法,在调用会触发控制器的viewWillLayoutSubviews方法,调用完毕后触发viewDidLayoutSubviews,这两个方法不把它们当成生命周期函数看待,因为其驱动因素是layoutSubViews方法。

viewDidAppear

视图显示到屏幕上。此时控制器的视图已经适配了屏幕,并且子视图都布局完毕。

viewWillDisappear

视图即将消失

viewDidDisappear

视图从屏幕上消失

APP启动原理

执行main函数,main函数内部执行UIApplicationMain方法,下面都是该方法做的事:

  1. 创建UIApplication单例对象。
  2. 创建UIApplication的UIAppDelegate对象。
  3. 开启消息循环。
  4. 加载info.plist文件,读取Main storyboard file base name字段的值,若值不为空,则从storyboard中加载控制器,执行5;否则执行6。

  5. 如下

    • 系统自行创建UIAppDelegate的UIWindow对象,加载storyboard中的initial view controller,并将其作为UIWindow的rootViewController。
    • 通知AppDelegate启动APP,调用启动方法didFinishLaunchingWithOptions。
    • 将AppDelegate的window作为keyWindow显示。这个时候才会去加载rootViewController的view,执行rootViewController的生命周期函数,最后rootViewController的view被显示在屏幕上。
  6. 通 AppDelegate启动app,调用启动方法didFinishLaunchingWithOptions。由于系统并没有创建AppDelegate的UIWindow对象,因此需要在启动方法中自行创建,并配置好rootViewController,最后手动显示window。

self.view高度

当不显示导航栏或者显示的导航栏为半透明时,view坐标原点在屏幕左上角,这种情况下view最终的高度为屏幕高度;当显示的导航栏不透明时,view的坐标原点在导航栏左下角,这时view最终的高度为屏幕高度-64(之所以说最终是因为view在即将显示时才去适配屏幕大小,再此之前加载的view为多大frame即为多大)。

因此为了避免在有不透明导航栏的情况下self.view.frame.height为屏幕高度减64的特例,通常做法是在viewDidLoad异步执行一个方法,在该方法中代替viewDidLoad做自定义视图等相关操作。
dispatch_async(dispatch_get_main_queue(), ^{
[self initBaseView];
});
由于异步执行, [self initBaseView] 会等到主队列中的生命周期函数(一直到viewDidAppear)执行完毕才执行,这时候获取到的self.view.frame.height就是能够操作的高度,即在无导航栏或者有透明导航栏时,高度为屏幕高度;有不透明导航栏时,高度为屏幕高度-64。

状态栏 导航栏

状态栏高度为20,导航栏高度为44。在没有导航栏的情况下,状态栏背景颜色为透明色。当有导航栏的情况下,状态栏背景颜色和导航栏一致(通过barTintColor属性设置)。

状态栏、导航栏并不是当前控制器的view的一部分!状态栏由APP维护,导航栏则是导航控制器的一部分。

导航栏隐藏遇到的坑爹问题

问题上下文如下:
一个导航栏下面紧跟着一个搜索栏,点击搜索框输入内容时,动态隐藏导航栏,搜索栏跟着上移,但是并不是移到屏幕顶端,而是距屏幕顶端20高度处。原因是什么?要怎么做才能移动到屏幕顶端?

原因在于自动布局的时候搜索栏的topSpace是根据Top Layout Guide设置的,并不是根据view设置的。如下图:

导航栏隐藏之前Top Layout Guide为导航栏的bottom,当导航栏隐藏之后,虽然导航栏frame从 {{0, 20}, {414, 44}} 变为 {{0, -44}, {414, 44}} ,但是搜索框的topSpace所依据的Top Layout Guide却变为状态栏的bottom,因此搜索栏未能跟随导航栏移动到屏幕顶端。

解决办法是将topSpace约束相对于view设置即可。即设置的时候选择上图中的View。在导航栏隐藏之前,View的坐标原点位于导航栏左下角(假设导航栏为非透明的),当导航栏隐藏之后,View的左边原点变为屏幕左上角,因此searchBar会跟着上移到屏幕顶端

奇葩属性automaticallyAdjustsScrollViewInsets

今天在捣鼓UI时遇到了UITableView显示内容比预想位置低了不少情况,感觉很莫名其妙。后来google了一下,发现是automaticallyAdjustsScrollViewInsets这个属性在搞鬼。automaticallyAdjustsScrollViewInsets是iOS7出的试图控制器的属性,官方说明如下:

The default value of this property is YES, which lets container view controllers know that they should adjust the scroll view insets of this view controller’s view to account for screen areas consumed by a status bar, search bar, navigation bar, toolbar, or tab bar. Set this property to NO if your view controller implementation manages its own scroll view inset adjustments.

听起来比较抽象,简而言之就是将该属性设置为YES之后,视图控制器就会自动调整其view中的scrollView控件的contentInset,具体怎么调整,一头雾水!

于是我在工程中把视图控制器的该属性设置为NO,问题确实解决了。不过似乎这个属性的“自动调整”反而给我帮了倒忙了!另外发现网上好多人多这个属性几乎没什么用处,唯一有用的环境如下:

在一个视图控制器中全屏添加一个UITableView(UIScrollView),假如当前导航栏是半透明的,细心的同学会发现,UITableView在显示时顶部是贴着导航栏下沿的,而预想应当是紧贴屏幕顶端才是(edgesForExtendedLayout属性为默认的UIRectEdgeAll)。事实上,UITableView确实是贴着屏幕顶端的,我们看上去贴着导航栏下沿,只是因为控制器自动对UITableView的contentInset做了调整,打印查看是(64,0,0,0),这就解释得通了。这完全是automaticallyAdjustsScrollViewInsets的功劳,默认设置为YES。

不过话说回来,只是少写了一条手动设置contentInset的代码…因此如果编码过程中出现莫名其妙的UIScrollView显示位置异常,很可能就是这个属性在作祟!个人认为这个属性还是比较奇葩的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值