iOS Programming-第三章 Views and the View Hierarchy

視圖和視圖層級


視圖基礎


視圖是

  • UIView 的一個實例, 或它的一個子類
  • 視圖知道怎么繪制自己
  • 能處理事件, 例如觸摸(touches)
  • 視圖存在于視圖層級中, 它的根是程序的窗口

視圖層級


每個應用程序都有一個 UIWindow 的單個實例用作程序中所有視圖的容器。UIWindowUIView 的子類, 所以窗口自己也是一個視圖献起。窗口在程序啟動時被創(chuàng)建性雄。一旦窗口創(chuàng)建完成, 其它視圖就會被添加到窗口上阅羹。

當其它視圖被添加到窗口中時, 它就是窗口的子視圖讹挎。窗口的子視圖還可以有子視圖, 結果就是視圖對象的層級, 而 window 窗口是它們的根(root)真友。

一旦視圖層級創(chuàng)建完成, 它會被畫到屏幕上薯鳍。這個過程可以被分為2步:

  • 視圖層級中的每個視圖, 包括窗口, 繪制自己对扶。它們把自己渲染到它的圖層上(layers), 你可以把 layers 看作一張位圖袁辈。(layer 是 CALayer 的一個實例)
  • 所有視圖的 layers 被組合到屏幕上

視圖和 Frames


當你用程序初始化一個視圖時, 使用 init(frame:) 指定初始化函數(shù)菜谣。(designated initializer) 這個函數(shù)接收一個參數(shù), 即 CGRect , 它會變成視圖的 frame, 即UIView 的一個屬性。

var frame: CGRect

視圖的frame 指定了視圖的大小和它相對于父視圖的位置晚缩。因為視圖的大小總是由它的 frame 指定, 視圖的形狀總是矩形尾膊。

CGRect 包含成員 originsizeorigin 是類型為 CGPoint 的結構體, 它包含兩個 CGFloat 屬性: x 和 y荞彼。 size是類型為 CGSize 的結構體, 它包含兩個 CGFloat 屬性: width 和 height冈敛。

在 Xcode 中新建一個叫做 WorldTrotter 的項目, 刪除 ViewController.swift 中的其它方法, 只保留如下結構:

import UIKit

class ViewController: UIViewController {

}

在視圖控制器的 view 被載入到內存中之后, 它的 viewDidLoad 方法會被調用。這個方法給了你自定義視圖層級的機會, 所以那是一個添加你實際視圖的好地方鸣皂。

在 ViewController.swift 中重寫 viewDidLoad 方法抓谴。創(chuàng)建一個 CGRect 作為 UIView 的 frame。然后創(chuàng)建一個 UIView 的實例, 并設置它的 backgroundColor 屬性為藍色寞缝。最后, 把 UIView 作為視圖控制器的 view 的子視圖添加上去以使它成為視圖層級的一部分癌压。

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let firstFrame = CGRect(x: 160, y: 240, width: 100, height: 150)
        let firstView  = UIView(frame: firstFrame)
        firstView.backgroundColor = UIColor.blueColor()
        view.addSubview(firstView)
    }
}

為了創(chuàng)建一個 CGRect, 你要使用它的構造函數(shù)并為 origin.x 、 origin.y荆陆、size.width滩届、size.height 傳入值。

為了設置 backgroundColor, 你要使用 UIColor 的類方法 blueColor()被啼。這是一個初始化 UIColor 實例為藍色的便利方法帜消。有很多 UIColor 便利方法用于普通顏色, 例如 greenColor()棠枉、blackColor()clearColor()

構建并運行該程序(Command-R)泡挺。 你會看到一個藍色的矩形, 它就是 UIView 的一個實例辈讶。 frame 中的這些值都是點(points), 而不是像素。如果那些值是像素, 則它們在不同分辨率的設備之間會不一致(例如 Retina vs. 非 Retina)娄猫。根據(jù)顯示器中像素的多少, 點也會表示多少數(shù)量的像素贱除。尺寸、位置稚新、線和曲線總是以點來描述的。

UIView 的每個實例都有一個 superview 屬性跪腹。當你添加一個視圖作為另一個視圖的子視圖時, 反轉的關系就會自動建立褂删。這時, UIViewsuperview 就是 UIWindow

讓我們測試下視圖層級冲茸。首先, 在 ViewController.swift 中創(chuàng)建另外一個 UIView 實例, 使用不同的 frame 和背景色屯阀。

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let firstFrame = CGRect(x: 160, y: 240, width: 100, height: 150)
        let firstView  = UIView(frame: firstFrame)
        firstView.backgroundColor = UIColor.blueColor()
        view.addSubview(firstView)

        let secondFrame = CGRect(x: 20, y: 30, width: 50, height: 50)
        let secondView  = UIView(frame: secondFrame)
        secondView.backgroundColor = UIColor.greenColor()
        view.addSubview(secondView)
    }
}

現(xiàn)在我們調整一下視圖層級。

...

let secondView = UIView(frame: secondFrame)
secondView.backgroundColor = UIColor.greenColor()

firstView.addSubview(secondView)

現(xiàn)在綠色視圖在藍色視圖里面了轴术。

自動布局


默認地, 每個視圖有一個對齊矩形, 并且每個視圖層級都使用自動布局难衰。

對齊矩形和 frame 很相似。實際上這兩個矩形經(jīng)常是相似的逗栽。而 frame 包圍整個視圖, 對齊矩形只包圍你想用于對齊意圖的內容盖袭。圖 3.17 展示了它倆之間的不同。

img

你不能直接定義 view 的對齊矩形彼宠。你沒有足夠的信息(例如屏幕尺寸)來做到那鳄虱。相反, 你提供了一系列約束。 放在一塊兒, 這些約束能使系統(tǒng)確定布局屬性, 因此還有對齊矩形, 對于視圖層級中的每個視圖凭峡。

約束


不是每個布局屬性都需要一個約束拙已。如果你指定了最邊距和視圖的寬度, 那么視圖的右邊距就自動為了計算好了。

描述一個跟屏幕尺寸無關的視圖的約束, 例如你想要你最上面的 label 的約束為:

  • 距離屏幕最上邊為 8 個點
  • 在它的父視圖中水平居中
  • 跟它的文本同高同寬

要在 Interface Builder 中把這個描述轉換為約束, 懂得怎么找到視圖的最近的兄弟視圖會有所幫助摧冀。最近的鄰居是在指定方向上最近的兄弟視圖倍踪。

img

如果一個視圖在指定方向上沒有任何兄弟視圖, 那么最近的鄰居就是它的父視圖, 也就是作為它的容器。

現(xiàn)在你能講清楚那個 Label 的約束了:

  1. 該 Label 的上邊距應該距離它的最近的鄰居(就是它的容器 — ViewController 中的 view) 8 個點索昂。
  2. 該 Label 的中心應該和它的父視圖的中心一樣建车。
  3. 該 Label 的寬度應該和以文本字體尺寸渲染的文本的寬度一樣
  4. 該 Label 的高度應該和以文本字體尺寸渲染的文本的高度相同。

固有內容尺寸


視圖的固有內容尺寸作為顯式的寬和高約束椒惨。如果你不指定明確測定寬度的約束, 那么視圖的寬就是它固有的寬度癞志。這同樣適用于高度。

現(xiàn)在我們對這 5 個 Labels 進行自動布局框产。

選擇最上面的那個 Label凄杯。 打開 Align 菜單并選擇 Horizontally in Container, 其中約束為 0错洁。確保 Update Frames 沒有被選中; 記住不要在視圖沒有足夠的約束之前更新 frame, 而這一個約束肯定不會提供足夠的信息來計算對齊矩形。繼續(xù)并添加一個約束戒突。

在畫布上選擇所有 5 個 Labels屯碴。同時給多個視圖添加約束也很方便。 打開 Pin 菜單并做如下選擇:

  1. 選擇最上面的 top 上邊距, 設置它的約束為 8
  2. Align 菜單中, 選擇 Horizontal Centers
  3. Updates Frames 菜單中, 選擇 Items of New Constraints

約束設置完成后的界面如下:

img
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末膊存,一起剝皮案震驚了整個濱河市导而,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌隔崎,老刑警劉巖今艺,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異爵卒,居然都是意外死亡虚缎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門钓株,熙熙樓的掌柜王于貴愁眉苦臉地迎上來实牡,“玉大人,你說我怎么就攤上這事轴合〈次耄” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵受葛,是天一觀的道長题涨。 經(jīng)常有香客問我,道長总滩,這世上最難降的妖魔是什么携栋? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮咳秉,結果婚禮上婉支,老公的妹妹穿的比我還像新娘。我一直安慰自己澜建,他們只是感情好向挖,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著炕舵,像睡著了一般何之。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咽筋,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天溶推,我揣著相機與錄音,去河邊找鬼。 笑死蒜危,一個胖子當著我的面吹牛虱痕,可吹牛的內容都是我干的。 我是一名探鬼主播辐赞,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼部翘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了响委?” 一聲冷哼從身側響起新思,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赘风,沒想到半個月后夹囚,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡邀窃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年荸哟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛔翅。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡敲茄,死狀恐怖位谋,靈堂內的尸體忽然破棺而出山析,到底是詐尸還是另有隱情,我是刑警寧澤掏父,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布笋轨,位于F島的核電站,受9級特大地震影響赊淑,放射性物質發(fā)生泄漏爵政。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一陶缺、第九天 我趴在偏房一處隱蔽的房頂上張望钾挟。 院中可真熱鬧,春花似錦饱岸、人聲如沸掺出。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽汤锨。三九已至,卻和暖如春百框,著一層夾襖步出監(jiān)牢的瞬間闲礼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留柬泽,地道東北人慎菲。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像聂抢,于是被迫代替她去往敵國和親钧嘶。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容