第一章 Views

view (UIView 对象或 UIView 的子类)知道怎么把自己绘制到界面的矩形区域中。由于 views 你的 app 才有一个可见的界面。创建和配置一个 view 可以极其简单, 例如你可以拖拽一个界面对象, 比如一个 UIButton 到 nib 编辑器的 view 中; 当 app 运行时, 按钮出现, 没什么问题。但是你也可以以强大的方式操作 views, 实时地。你的代码可以做某些或全部的描绘视图自己, 并展示其它物理变化, 还可以带有动画。

view 也是一个响应器(responder)(UIView 是 UIResponder 的子类)。这意味着 view 能经受用户交互, 例如轻敲和重击(taps and swipes)。因此, views 不仅是用户看见的界面的基础, 还是用户触摸的界面的基础。组织好你的 views 以使正确的视图对给定的触摸有反应。

视图层级(view hierarchy)是视图组织的主要模式。 视图可以有子视图; 子视图只有一个直接的父视图。因此会形成一个视图树。这个层级允许视图可以一块儿出现和消失。如果从界面中移除一个 view, 那么这个 view 的子视图也会被移除; 如果隐藏一个 view(使不可见), 那么它的子视图也是隐藏的; 如果移除一个 view, 那么它的子视图也随之移除; 并且 view 中的变化同样也被子视图共享。视图层级也是响应链的基础。

view 可能来自一个 xib, 也可以用代码创建。 为了平衡, 任何一种方法也不会比另一种更好; 它取决于你的需要和喜好, 还有你的 app 的总体架构。

The Window


视图层级的最上面是 app 的 window(窗口)。它是 UIWindow 的一个实例, 即 UIView 的一个子类。你的 app 应该只有一个主窗口(one main window)。 主窗口在 app 启动时被创建并且不能被摧毁或代替。主窗口也组成了背景, 是你所有其它可见视图的最终的父视图。其它 views 由于作为你的 app 窗口的子视图, 以某种深度, 而可见。

如果你的 app 可以在额外的屏幕上展示视图, 你需要创建额外的 UIWindow 来包含那些视图

app 的窗口必须在最开始时填满(fill)设备的屏幕。在窗口实例化时通过把 window 的 frame 设置为屏幕的 bounds 时确保了填满整个屏幕。如果你使用的是 main storyboard, UIApplicationMain 函数会在 app 启动时自动在幕后为你处理; 但是没有 main storyboard 的 app 也是可以的, 不过你得在 app 生命周期的早期自己创建 window 并设置它的 frame, 就像这样:

let w = UIWindow(frame: UIScreen.mainScreen().bounds)

在新的 iOS 9 中, 不使用 frame 来实例化UIWindow 也绰绰有余; 会为你把屏幕的 bounds 赋值给 window 的 frame 的:

let w = UIWindow()

window 必须也和 app 的生命期一样持久。为了做到这一点, app 的代理类(delegate class)拥有了一个带有强保留(strong retain)策略的 window 属性。当 app 启动时, UIApplicationMain函数实例化那个 app 代理类并保留(retain)那个结果实例。这就是 app 代理实例(the app delegate instance); 它绝对不会释放, 所以它持久到 app 的整个生命周期。然后该 window 实例被赋值给 app 代理实例的 window 属性; 因此 window 也持久到 app 的整个声明周期。

通常你不会手动并直接地在你的 main window 中存放任何视图内容。相反, 你会获得一个视图控制器并把它赋值给 main window 的 rootViewController 属性。 再一次地, 如果你正在使用 main stroyboard, 这会在幕后自动为你做好; 提到的那个视图控制器会成为你的 storyboard 的初始视图控制器。

当一个视图控制器变成 main window 的 rootViewController 时, 它的主视图(它的 view)成为你的 main window 仅有的一个直接子视图 — 该 mian window 的根视图(root view)。你的 main window 中的所有其它视图成为根视图的子视图。因此, 在视图层级中用户通常看到的最高等级的对象就是根视图。某种情况下, 用户可能有机会瞄到根视图后面的 window; 基于这个原因, 你可能想给 main window 设置一个可行的背景色(backgroundColor)。但这看起来不见得, 并且通常你没有理由去改变 window 自身的任何东西。

app 的界面直到包含 app 的 window 成为该 app 的 key window 时才可见。这通过调用 UIWindow 的实例方法 makeKeyAndVisible 来完成。

让我们总结一下初始化创建, 配置, 和 main window 的展示是怎么发生的。有 2 种情况需要考虑:

  • 带有 main storyboard 的 app

如果你的 app 拥有一个 main storyboard, 它在 Info.plist key 的 "Main storyboard file base name" (UIMainStoryboardFile)中指定 — 所有的 Xcode 7 app 模板中都是默认好的 — 然后 UIApplicationMain 实例化 UIWindow, 正确地设置它的 frame, 并把那个实例赋值给 app delegate 的 window 属性。此外, 它初始化了 storyboard 的初始视图控制器, 并把那个实例赋值给 window 的 rootViewController 属性。所有这些都是发生在 app delagate 的 application:didFinishLaunchingWithOptions: 被调用之前。

最后, UIApplictionMain 在 window 上调用 makeKeyAndVisible, 来展示你的 app 界面。这反过来自动让根视图控制器获取到它的主视图(通常从 nib 中加载), 其中 window 把它添加为它自己的根视图。这发生在 application:didFinishLaunchingWithOptions 被调用之后。

  • 不带 main storyboard 的 App

如果你的 app 不带 main storyboard, 那么 window 的创建和配置必须另辟蹊径。通常会使用代码。没有 Xcode 7 的 app 模板缺少 main storyboard, 但是假设你以一个 Single View Application 模板开始, 你可以按照下面的试验:

  1. 编辑 target。 在 General 面板, 选中 Main Interface 栏中的 "Main" 并删除(按下 Tab 来使该更改生效)。
  2. 从工程中删除 Main.storyboardViewController.swift
  3. 删除 AppDelegate.swift 中的全部内容

现在你拥有了一个含有一个 app target 但是没有 storyboard 和 代码的工程。为了让这个最小化的 app 能够工作, 你需要以这种方式编辑 AppDelegate.swift 以使用足够的代码在 app 启动时来创建和展示 window, 就像 Example 1-1 展示的那样。

Example 1-1 不带 storyboard 的 app delegate 类

import UIKit

@UIApplicationMain
class AppDelegate : UIResponder, UIApplicationDelegate {
    var window : UIWindow?
    func application(application: UIApplication, 
         didFinishLaunchingWithOptions lanuchOptions: [NSObject : AnyObject]?) 
         -> Bool {
             self.window = UIWindow()
             self.window!.rootViewController = UIViewController()
             self.window!.backgroundColor    = UIColor.whiteColor()
             self.window!.makeKeyAndVisible()
             return true
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,392评论 25 707
  • 概述 UIView或者它的子类知道怎样将自己绘制在一个矩形区域中。我们app所有可视的的界面来自于视图。创建和配置...
    smalldu阅读 859评论 0 6
  • 第一部分views 简介 A view is a unit of your app that knows how ...
    廖马儿阅读 487评论 0 1
  • “有本事别加靇霘皨箜!快乐英子,李彦国,武桂有什么的!”我道。“切!”妖道。 多么恐怖,简书有妖!这妖便是我姐啦!...
    刘婧_阅读 236评论 0 7
  • 是不是成长的路上,注定要经历? 是不是每一个经历,都会是一个成长? 离开校园,走上工作,经历最多的是变动,伤感最多...
    飒凉阅读 381评论 0 0