干貨-UIView你知道多少(轉(zhuǎn))

曾經(jīng)有人這么說過,在iphone里你看到的,摸到的,都是UIView,所以UIView在iphone開發(fā)里具有非常重要的作用。那么UIView我們到底知道多少呢。請看看下面的問題

如果這些你都知道,那么本文章的內(nèi)容就請繞道,如果你還不太清楚,我想看了下面的內(nèi)容,你就明白了。

1.bounds和frame分別表示什么?
2.ContentMode里UIViewContentModeScaleToFill代表什么?
3.contentStretch 里的指定UIView里縮放區(qū)域是如何計算的?
4.UIVIew里的哪些屬性變化可以用動畫來呈現(xiàn)?
5.UIKit的坐標(biāo)系和Core Graphics的坐標(biāo)系的差別是什么?

視圖和窗口展示了應(yīng)用的用戶界面,同時負(fù)責(zé)界面的交互。UIKit和其他系統(tǒng)框架提供了很多視圖,你可以就地使用而幾乎不需要修改。當(dāng)你需要展示的內(nèi)容與標(biāo)準(zhǔn)視圖允許的有很大的差別時,你也可以定義自己的視圖。

不管你是使用系統(tǒng)的視圖還是創(chuàng)建自己的視圖,你需要理解UIView和UIWindow類所提供的基本結(jié)構(gòu)。這些類提供了復(fù)雜的方法來管理視圖的布局和展示。理解這些方法的工作非常重要,使你在應(yīng)用發(fā)生改變時可以確認(rèn)視圖有合適的行為。

** 視圖架構(gòu) fundamentals **

大部分你想要可視化操作都是由視圖對象-即UIView類的實例-來進(jìn)行的。一個視圖對象定義了一個屏幕上的一個矩形區(qū)域,同時處理該區(qū)域的繪制和觸屏事件。一個視圖也可以作為其他視圖的父視圖,同時決定著這些子視圖的位置和大小。UIView類做了大量的工作去管理這些內(nèi)部視圖的關(guān)系,但是需要的時候你也可以定制默認(rèn)的行為。

視圖與Core Animation層聯(lián)合起來處理著視圖內(nèi)容的解釋和動畫過渡。每個UIKit框架里的視圖都被一個層對象支持(通常是一個CALayer類的實例),它管理管理著后臺的視圖存儲和處理視圖相關(guān)的動畫。然而,當(dāng)你需要對視圖的解釋和動畫行為有更多的控制權(quán)時,你可以使用層。

為了理解視圖和層之間的關(guān)系,我們可以借助于一些例子。圖1-1顯示了ViewTransitions樣例程序的視圖層次及其對底層Core Animation層的關(guān)系。應(yīng)用中的視圖包括了一個window(同時也是一個視圖),一個通用的表現(xiàn)得像一個容器視圖的UIView對象,一個圖像視圖,一個控制顯示用的工具條,和一個工具條按鈕(它本身不是一個視圖但是在內(nèi)部管理著一個視圖)。(注意這個應(yīng)用包含了一個額外的圖像視圖,它是用來實現(xiàn)動畫的)。為了簡化,同時因為這個視圖通常是被隱藏的,所以沒把它包含在下面的圖中。每個視圖都有一個相應(yīng)的層對象,它可以通過視圖礶r屬性被訪問。(因為工具條按鈕不是一個視圖,你不能直接訪問它的層對象。)在它們的層對象之后是Core Animation的解釋對象,最后是用來管理屏幕上的位的硬件緩存。

Figure 1-1 View architecture

使用Core Animation的層對象有很重要的性能意義。一個視圖對象的繪制代碼需要盡量的少被調(diào)用,當(dāng)它被調(diào)用時,其繪制結(jié)果會被Core Animation緩存起來并在往后可以被盡可能的重用。重用已經(jīng)解釋過的內(nèi)容消除了通常需要更新視圖的開銷昂貴的繪制周期。內(nèi)容的重用在動畫中特別重要,我們可以使用已有的內(nèi)容,這樣比創(chuàng)建新的內(nèi)容開銷更小。

視圖層次和子視圖管理

除了提供自己的內(nèi)容之外,一個視圖也可以表現(xiàn)得像一個容器。當(dāng)一個視圖包含其他視圖時,就在兩個視圖之間創(chuàng)建了一個父子關(guān)系。在這個關(guān)系中孩子視圖被當(dāng)作子視圖,父視圖被當(dāng)作超視圖。創(chuàng)建這樣一個關(guān)系對應(yīng)用的可視化和行為都有重要的意義。

在視覺上,子視圖隱藏了父視圖的內(nèi)容。如果子視圖是完全不透明的,那么子視圖所占據(jù)的區(qū)域就完全的隱藏了父視圖的相應(yīng)區(qū)域。如果子視圖是部分透明的,那么兩個視圖在顯示在屏幕上之前就混合在一起了。每個父視圖都用一個有序的數(shù)組存儲著它的子視圖,存儲的順序會影響到每個子視圖的顯示效果。如果兩個兄弟子視圖重疊在一起,后來被加入的那個(或者說是排在子視圖數(shù)組后面的那個)出現(xiàn)在另一個上面。

父子視圖關(guān)系也影響著一些視圖行為。改變父視圖的尺寸會連帶著改變子視圖的尺寸和位置。在這種情況下,你可以通過合適的配置視圖來重定義子視圖的尺寸。其他會影響到子視圖的改變包括隱藏父視圖,改變父視圖的alpha值,或者轉(zhuǎn)換父視圖。

視圖層次的安排也會決定著應(yīng)用如何去響應(yīng)事件。在一個具體的視圖內(nèi)部發(fā)生的觸摸事件通常會被直接發(fā)送到該視圖去處理。然而,如果該視圖沒有處理,它會將該事件傳遞給它的父視圖,在響應(yīng)者鏈中以此類推。具體視圖可能也會傳遞事件給一個干預(yù)響應(yīng)者對象,像視圖控制器。如果沒有對象處理這個事件,它最終會到達(dá)應(yīng)用對象,此時通常就被丟棄了。
獲取更多關(guān)于如何創(chuàng)建視圖層次,查看 creating and managing a view hierarchy

視圖繪制周期

UIView類使用一個點播繪制模型來展示內(nèi)容。當(dāng)一個視圖第一次出現(xiàn)在屏幕前,系統(tǒng)會要求它繪制自己的內(nèi)容。在該流程中,系統(tǒng)會創(chuàng)建一個快照,這個快照是出現(xiàn)在屏幕中的視圖內(nèi)容的可見部分。如果你從來沒有改變視圖的內(nèi)容,這個視圖的繪制代碼可能永遠(yuǎn)不會再被調(diào)用。這個快照圖像在大部分涉及到視圖的操作中被重用。

如果你確實改變了視圖內(nèi)容,也不會直接的重新繪制視圖內(nèi)容。相反,使用setNeedsDisplay或者setNeedsDisplayInRect:方法廢止該視圖,同時讓系統(tǒng)在稍候重畫內(nèi)容。系統(tǒng)等待當(dāng)前運(yùn)行循環(huán)結(jié)束,然后開始繪制操作。這個延遲給了你一個機(jī)會來廢止多個視圖,從你的層次中增加或者刪除視圖,隱藏,重設(shè)大小和重定位視圖。所有你做的改變會稍候在同一時間反應(yīng)。
注意:改變一個視圖的幾何結(jié)構(gòu)不會自動引起系統(tǒng)重畫內(nèi)容。視圖的contentMode屬性決定了改變幾何結(jié)構(gòu)應(yīng)該如果解釋。大部分內(nèi)容模式在視圖的邊界內(nèi)拉伸或者重定位了已有快照,它不會重新創(chuàng)建一個新的快照。獲取更多關(guān)于內(nèi)容模式如果影響視圖的繪制周期,查看 content modes

當(dāng)繪制視圖內(nèi)容的時候到了時,真正的繪制流程會根據(jù)視圖及其配置改變。系統(tǒng)視圖通常會實現(xiàn)私有的繪制方法來解釋它們的視圖,(那些相同的系統(tǒng)視圖經(jīng)常開發(fā)接口,好讓你可以用來配置視圖的真正表現(xiàn)。)對于定制的UIView子類,你通常可以覆蓋drawRect:方法并使用該方法來繪制你的視圖內(nèi)容。也有其他方法來提供視圖內(nèi)容,像直接在底部的層設(shè)置內(nèi)容,但是覆蓋drawRect:時最通用的技術(shù)

內(nèi)容模式

視圖的內(nèi)容模式控制著視圖如何回收內(nèi)容來響應(yīng)視圖幾何結(jié)構(gòu)的變化,也控制著是否需要回收內(nèi)容。當(dāng)一個視圖第一次顯示時,它通常會解釋內(nèi)容,其結(jié)果會被底層的層級樹捕獲為一張位圖。在那之后,改變視圖的幾何結(jié)構(gòu)不會導(dǎo)致重新創(chuàng)建位圖。相反,視圖中contentMode屬性的值決定著這張位圖是否該被拉伸,以適應(yīng)新的邊界或者只是簡單的被放到角落或者視圖的邊界。

視圖的內(nèi)容模式在你進(jìn)行如下操作時被應(yīng)用:

1.改變視圖frame或者bounds矩形的寬度或者高度時。
2.賦值給視圖的transform屬性,新的轉(zhuǎn)換包括一個放縮因子。

大部分視圖的contentMode值是UIViewContentModeScaleToFiill,它使視圖的內(nèi)容被放縮到適合新框架的值。Figure 1-2展示了使用其他可用的內(nèi)容模式的結(jié)果。正如你在圖中所看到的那樣,不是所有的內(nèi)容模式都可以填充視圖的范圍,可以的模式可能會扭曲內(nèi)容。

內(nèi)容模式很好的支持了視圖的內(nèi)容回收,但是當(dāng)你想視圖在放縮和重設(shè)尺寸的操作中重繪你也可以用UIViewContentModeRedraw內(nèi)容模式。設(shè)置這個值繪強(qiáng)制系統(tǒng)調(diào)用視圖的drawRect:方法來響應(yīng)幾何結(jié)構(gòu)的變化。通常來講,你應(yīng)該盡可能的避免使用這個模式,同時你不應(yīng)該在標(biāo)準(zhǔn)的系統(tǒng)視圖中使用這個模式。

獲取更多骨干與可用的內(nèi)容模式,查看UIView Class Reference

Figure 1-2

拉伸視圖

你可以指定視圖的某部分為可拉伸的,以便當(dāng)視圖的尺寸改變時只有可拉伸的部分被影響到??衫斓牟糠滞ǔ=o按鈕或者其他的部分為重復(fù)模式的視圖。由你指定的可拉伸區(qū)域允許沿著兩條或者其中一條軸拉伸。當(dāng)然,當(dāng)一個視圖沿著兩條軸拉伸的時候,視圖的邊界必須也定義了一個重復(fù)的模式來避免任何的扭曲。Figure1-3展示了這種扭曲在視圖里是怎么表現(xiàn)自己的。每個視圖里的原始像素的顏色都自我復(fù)制,以便可以填充更大視圖的相應(yīng)區(qū)域。

Figure 1-3 拉伸一個按鈕的背景

你可以用contentStretch屬性來定義一個視圖的可拉伸區(qū)域。這個屬性的值一個邊的值被標(biāo)準(zhǔn)化為0.0到1.0之間的矩形。當(dāng)拉伸這個視圖時,系統(tǒng)將視圖的當(dāng)前邊界值和放縮因子乘以標(biāo)準(zhǔn)值,以便決定哪些像素需要被拉伸。使用標(biāo)準(zhǔn)值可以減輕每次改變視圖的邊界值都更新contentStretch屬性的需要。

視圖的內(nèi)容模式也在決定如何視圖的可拉伸區(qū)域的使用中扮演著重要的角色。只有當(dāng)內(nèi)容模式可能繪引起視圖內(nèi)容放縮的時候可拉伸區(qū)域才會被使用。這意味這你的可拉伸視圖只被UIViewContentModeScaleToFill, UIViewContentModeScaleAspectFit和UIViewContentModeScaleAspectFill內(nèi)容模式。如果你指定了一個將內(nèi)容彈到邊界或者角落的內(nèi)容模式(這樣就沒有真正的放縮內(nèi)容),這個視圖會忽視可拉伸區(qū)域。

注意:當(dāng)需要創(chuàng)建一個可拉伸UIImage對象作為視圖的背景時,使用contentStretch屬性是推薦的??衫煲晥D完全被Core Animation層處理,這樣性能通常更好。

嵌入式動畫支持

使用層對象來支持視圖的其中一個利益是你可以輕松的用動畫處理視圖相關(guān)的改變。動畫是與用戶進(jìn)行信息交流的一個有用的方法,而且應(yīng)該總是在進(jìn)行應(yīng)用設(shè)計的過程中考慮使用動畫。UIView類的很多屬性是動畫化的-也就是,可以半自動的從一個值動畫的變化到另一個值。為了實現(xiàn)這樣一個動畫,你需要做的只是:

1 告訴UIKit你想要實現(xiàn)一個動畫
2 改變這個屬性的值

在一個UIView對象中有以下的動畫化屬性:

frame - 你可以使用這個來動畫的改變視圖的尺寸和位置
bounds - 使用這個可以動畫的改變視圖的尺寸
center - 使用這個可以動畫的改變視圖的位置
transform - 使用這個可以翻轉(zhuǎn)或者放縮視圖
alpha - 使用這個可以改變視圖的透明度
backgroundColor - 使用這個可以改變視圖的背景顏色
contentStretch - 使用這個可以改變視圖內(nèi)容如何拉伸

動畫的一個很重要的地方是用于從一組視圖到另一組視圖的過渡。通常來說,會用一個視圖控制器來管理關(guān)系到用戶界面的主要變更的動畫。例如,涉及到從高層到底層信息的導(dǎo)航的界面,通常會使用一個導(dǎo)航控制器來管理視圖的過渡,這些視圖顯示了數(shù)據(jù)的每一個連續(xù)層面。然而,你也可以使用動畫來創(chuàng)建兩組視圖的過渡,而不是視圖控制器。當(dāng)你想用一個系統(tǒng)提供的視圖控制器無法支持的導(dǎo)航方案時你可能會這樣做。

除了用UIKit類可以創(chuàng)建動畫外,你也可以用Core Animation層來創(chuàng)建動畫。在更低層你有更多的在時間或者動畫屬性上的控制權(quán)。

獲取更多關(guān)于如何創(chuàng)建一個基于視圖的動畫,查看 Animations
獲取更多關(guān)于使用Core Animation創(chuàng)建動畫的信息,查看Core Animation Programming Guide和Core Animation Cookbook.

視圖幾何結(jié)構(gòu)和坐標(biāo)系統(tǒng)

UIKit的默認(rèn)坐標(biāo)系統(tǒng)把原點設(shè)置在左上角,兩條軸往下和右擴(kuò)展。做標(biāo)志被表示為浮點數(shù),這樣允許內(nèi)容的精確布局和定位而不管底層的屏幕。Figure1-4展示了相對于屏幕的坐標(biāo)系統(tǒng)。除了屏幕坐標(biāo)系統(tǒng)窗口和視圖也定義了它們自己的本地坐標(biāo)系統(tǒng),這樣允許你指定相對于視圖或者窗口原點的坐標(biāo)而不是屏幕。

Figure 1-4 UIKit中的坐標(biāo)系統(tǒng)

因為每個視圖和窗口都定義了它自己的本地坐標(biāo)系統(tǒng),你需要留意在任何時間內(nèi)是哪個坐標(biāo)系統(tǒng)在起作用。每次繪制或者改變一個視圖都是基于一個坐標(biāo)系統(tǒng)的。在某些繪制中會基于視圖本身的坐標(biāo)系統(tǒng)。在某些幾何結(jié)構(gòu)變更中是基于父視圖的坐標(biāo)系統(tǒng)的。UIWindow和UIView類都包含了幫助你從一個坐標(biāo)系統(tǒng)轉(zhuǎn)換到另一個的方法。

重要:一些iOS技術(shù)定義了默認(rèn)的坐標(biāo)系統(tǒng),它們的原點和方向與UIKit的不同。;例如,Core Graphics和OpenGL ES的坐標(biāo)系統(tǒng)是原點在可視區(qū)域的左下角,而y軸往上遞增。當(dāng)繪制或者創(chuàng)建內(nèi)容時,你的代碼應(yīng)該考慮到一些不同并且適應(yīng)坐標(biāo)值。

frame, bounds和center屬性之間的關(guān)系:

視圖對象使用frame, bounds和center屬性來跟蹤它的尺寸和位置:
frame屬性包含了frame矩形,指定了在父視圖坐標(biāo)系統(tǒng)中該視圖的尺寸和位置。
center屬性包含了在父視圖坐標(biāo)系統(tǒng)中的已知中心點。
bounds屬性包含了邊界矩形,指定了在視圖本地坐標(biāo)系統(tǒng)中視圖的尺寸。

主要使用center和frame屬性來控制當(dāng)前視圖的幾何結(jié)構(gòu)。例如,當(dāng)在運(yùn)行時構(gòu)建你的視圖層次或者改變視圖的尺寸或者位置時你可以使用這些屬性。如果你只是要改變視圖的位置,那么推薦使用center屬性。center屬性的值永遠(yuǎn)是可用的,即使添加了放縮或者轉(zhuǎn)換因子到視圖的轉(zhuǎn)換矩陣當(dāng)中。但是對于frame屬性卻不是,當(dāng)視圖的轉(zhuǎn)換矩形不等于原始矩陣時它被當(dāng)作時無效的。

在繪制的過程中主要使用bounds屬性。這個邊界矩陣在視圖的本地坐標(biāo)系統(tǒng)被解釋。這個矩形的默認(rèn)原點是(0, 0),它的尺寸也適應(yīng)frame矩形的尺寸。任何繪制在這個矩形當(dāng)中的東西都是該視圖的可視內(nèi)容的一部分。如果你改變了bounds矩形的原點,任何你繪制在新矩形的東西都會變成該視圖可視內(nèi)容的一部分。

Figure1-5展示了一個圖像視圖的frame和bounds矩形之間的關(guān)系。圖中,圖像視圖的右上角被定位在父視圖坐標(biāo)系統(tǒng)的(40, 40),它的矩形尺寸為240x380。對于bounds矩形,原點是(0, 0),矩形尺寸也是240x380。

Figure 1-5 視圖frame和bounds之間的關(guān)系

即使你可以獨立的改變frame,bounds和center屬性,其中一個改變還是會影響到另外兩個屬性:

1.當(dāng)你設(shè)置了frame屬性,bounds屬性的尺寸值也改變來適應(yīng)frame矩形的新尺寸。center屬性也會改變?yōu)樾耭rame矩形的中心值。
2.當(dāng)你設(shè)置了center屬性,frame的原點也會相應(yīng)的改變。
3.當(dāng)你設(shè)置了bounds屬性,frame屬性會改變以適應(yīng)bounds矩形的新尺寸。

視圖的框架默認(rèn)不會被它的父視圖框架裁剪。這樣的化,任何放置在父視圖外的子視圖都會被完整的解釋。你可以改變這種行為,改變父視圖的clipsToBounds屬性就可以。不管子視圖是否在視覺上被裁剪,觸屏事件總是發(fā)生在目標(biāo)視圖父視圖的bounds矩形。換句話說,如果觸摸位于父視圖外的那部分視圖,那么該事件不會被發(fā)送到該視圖。

坐標(biāo)系統(tǒng)轉(zhuǎn)換矩陣

坐標(biāo)系統(tǒng)轉(zhuǎn)換矩陣給改變視圖(或者是它的視圖)提供了一個輕松和簡易的方法。一個仿射轉(zhuǎn)換是一個數(shù)學(xué)矩陣,它指定了在坐標(biāo)系統(tǒng)中的點是怎么被映射到另一個坐標(biāo)系統(tǒng)中的點。你可以對整個視圖應(yīng)用仿射轉(zhuǎn)換,以基于其父視圖來改變視圖的尺寸,位置或者朝向。你也可以在你的繪制代碼中應(yīng)用仿射轉(zhuǎn)換,以對已解釋內(nèi)容的獨立部分實現(xiàn)相同的操控。如何應(yīng)用仿射轉(zhuǎn)換是基于這樣的上下文的:

為了修改整個視圖,可以修改視圖transform屬性的仿射轉(zhuǎn)換值。

為了在視圖中的drawRect:方法中修改內(nèi)容的指定部分,可以修改與當(dāng)前圖形上下文相關(guān)的仿射轉(zhuǎn)換。

當(dāng)你想實現(xiàn)動畫時,通??梢孕薷囊晥D的transform屬性值。例如,你可以使用這個屬性來制作一個視圖圍繞中心點翻轉(zhuǎn)的動畫。你不應(yīng)該在其父視圖的坐標(biāo)空間中用這個屬性來永久的改變你的視圖,像修改它的位置和尺寸。對于這種類型的改變,你可以修改視圖的frame矩形。
注意:當(dāng)修改視圖的transform屬性值時,所有的轉(zhuǎn)換都是基于視圖的中心點來實現(xiàn)的。

在視圖的drawRect:方法中,你可以使用仿射轉(zhuǎn)換來定位或者翻轉(zhuǎn)你想要繪制的項目。相對于在視圖某些部位中修正對象的位置,我們更傾向于相對于一個固定點去創(chuàng)建對象,通常是(0, 0),同時在繪制之前使用轉(zhuǎn)換來定位對象。這樣的話,如果在視圖中對象的位置改變了,你要做的只是修改轉(zhuǎn)換矩陣,這樣比為對象重新創(chuàng)建新的位置性能更好開銷更低。你可以通過使用CGContextGetCTM方法來獲取關(guān)于圖形上下文的仿射轉(zhuǎn)換,同時可以用Core Graphics的相關(guān)方法在繪制中來設(shè)置或者修改這個轉(zhuǎn)換矩陣。

當(dāng)前轉(zhuǎn)換矩陣(CTM)是一個在任何時候都被使用的仿射矩陣。當(dāng)操控整個視圖的幾何結(jié)構(gòu)時,CTM就是視圖transform屬性的值。在drawRect:方法中,CTM是關(guān)于圖形上下文的仿射矩陣。

每個子視圖的坐標(biāo)系統(tǒng)都是構(gòu)建在其祖先的坐標(biāo)系統(tǒng)之上的。所以當(dāng)你修改一個視圖的transform屬性,這個改變會影響到視圖及其所有的子視圖。然而,這些改變只會影響到屏幕上視圖的最終解釋。因為每個視圖都負(fù)責(zé)繪制自己的內(nèi)容和對自己的子視圖進(jìn)行布局,所以在繪制和布局的過程中它可以忽略父視圖的轉(zhuǎn)換。

Figure1- 6描述了在解釋的時候,兩個不同的轉(zhuǎn)換因子是如何在視覺上組合起來的。在視圖的drawRect:方法中,對一個形狀應(yīng)用一個45度的轉(zhuǎn)換因子會使該形狀翻轉(zhuǎn)指定的角度。另外加上一個45度的轉(zhuǎn)換因子會導(dǎo)致整個形狀翻轉(zhuǎn)90度。這個形狀對于繪制它的視圖來講仍然只是翻轉(zhuǎn)了45度,但是視圖自己的轉(zhuǎn)換讓它看起來像使翻轉(zhuǎn)了90度。

Figure 1-6 翻轉(zhuǎn)一個視圖和它的內(nèi)容

重要:如果一個視圖的transform屬性不是其定義時轉(zhuǎn)換矩陣,那么視圖的frame屬性是未定義的而且必須被忽略。當(dāng)對視圖應(yīng)用轉(zhuǎn)換時,你必須使用視圖的bounds和center屬性來獲取視圖的位置和尺寸。子視圖的frame矩形仍然是有效的,因為它們與視圖的bounds相關(guān)。

獲取更多關(guān)于在運(yùn)行時修改視圖的transform屬性,查看 “Translating, Scaling, and Rotating Views.”獲取更多如何在繪制過程中使用轉(zhuǎn)換來定位內(nèi)容,查看 Drawing and Printing Guide for iOS.

點與像素

在iOS中,所有的坐標(biāo)值和距離都被指定為使用浮點數(shù),其單元值稱為點。點的數(shù)量隨著設(shè)備的不同而不同,而且彼此不相關(guān)。要明白關(guān)于點的最主要一點是它們提供了一個繪制用的固定框架。

Table 1-1 列出了不同iOS設(shè)備的分辨率(點度量)。前為寬后為長。只要你依照這些屏幕的尺寸來設(shè)計用戶界面,你的視圖就回被相應(yīng)的設(shè)備正確顯示。

Table 1-1

Device Screen dimensions (in points)
iPhone and iPod touch 320 x 480
iPad 768 x 1024

每一種使用基于點度量系統(tǒng)的設(shè)備都定義了一個用戶坐標(biāo)空間。這是幾乎在你所有的代碼都會用到的標(biāo)準(zhǔn)坐標(biāo)空間。例如,當(dāng)你要操控視圖的幾何結(jié)構(gòu)或者調(diào)用Core Graphics方法來繪制內(nèi)容時會用到點和用戶坐標(biāo)空間。即使有時用戶坐標(biāo)空間里的坐標(biāo)時直接映射到設(shè)備屏幕的像素,你還是永遠(yuǎn)不應(yīng)該假設(shè)這是永遠(yuǎn)不變的。相反,你應(yīng)該記?。阂粋€點并不一定對應(yīng)著屏幕上的一個像素

在設(shè)備層面,所有由你指定的視圖上的坐標(biāo)在某些點上必須被轉(zhuǎn)化成像素。然而,從用戶坐標(biāo)空間上的點到設(shè)備坐標(biāo)空間上的像素通常由系統(tǒng)來處理。UIKit和Core Graphics都主要使用基于向量的繪制模型,所有的坐標(biāo)值都被指定為使用點。這樣,如果你用Core Graphics畫了一條曲線,你會用一些值來指定這條曲線,而不管底層屏幕使用怎樣的解決方法。

當(dāng)你需要處理圖像或者其他基于像素的技術(shù),像OpenGL ES時,iOS會幫你管理這些像素。對于存儲為應(yīng)用程序的束中的資源的靜態(tài)圖像文件,iOS定義了一些約定,可以指定不同像素密度的圖像,也可以在加載圖像時最大限度的適應(yīng)當(dāng)前屏幕的解決方案。視圖也提供了關(guān)于當(dāng)前放縮因子的信息,以便你可以適當(dāng)?shù)恼{(diào)整任何基于像素的繪制代碼來適應(yīng)有更高級解決方案的屏幕。在不同屏幕的解決方案中處理基于像素內(nèi)容的技術(shù)可以在"Supporting High-Resolution Screens"和"Drawing and Printing Guide for iOS"找到描述。

**視圖的運(yùn)行時交互模型 **

當(dāng)用戶和界面進(jìn)行交互時,或者由代碼程序性的改變一些東西時,一系列復(fù)雜的事件就會發(fā)生在UIKit的內(nèi)部來處理這些交互。在這個系列中的某些點,UIKit喚出你的視圖類,同時給它們一個機(jī)會去響應(yīng)程序的行為。理解這些喚出點對于理解視圖在哪里融入系統(tǒng)很重要。Figure 1-7 展示了這些事件的基本序列,從用戶觸屏開始到圖形系統(tǒng)更新屏幕內(nèi)容來響應(yīng)結(jié)束。同樣的事件序列也會發(fā)生在任何程序性啟動的動作。

Figure 1-7 UIKit 與視圖對象進(jìn)行交互

以下的步驟分解了圖1-7中的事件序列,既解釋了在每一步發(fā)生了什么,也解釋了應(yīng)用如何響應(yīng)

1.用戶觸屏
2.硬件報告觸摸事件給UIKit框架
3.UIKit框架將觸摸事件打包成UIEvent對象,同時分發(fā)給適合的視圖。(對于UIKit框架如何提交事件給視圖的詳細(xì)解釋,查看 Event Handing Guide for iOS)
4.視圖中的事件處理代碼可能進(jìn)行以下的動作來響應(yīng):

改變視圖或者其子視圖的屬性(frame, bounds, alpha, 等等)
調(diào)用setNeedsLayout方法以標(biāo)記該視圖(或者它的子視圖)為需要進(jìn)行布局更新
調(diào)用setNeedsDisplay或者setNeedsDisplayInRect:方法以標(biāo)記該視圖(或者它的子視圖)需要進(jìn)行重畫
通知一個控制器關(guān)于一些數(shù)據(jù)的更新
當(dāng)然,哪些事情要做,哪些方法要被調(diào)用是由視圖來決定的。

5.如果一個視圖的幾何結(jié)構(gòu)改變了,UIKit會根據(jù)以下幾條規(guī)則來更新它的子視圖:

a.如果自動重設(shè)尺寸的規(guī)則在發(fā)生作用,UIKit會根據(jù)這些規(guī)則來調(diào)整視圖。獲取更多關(guān)于自動重設(shè)尺寸規(guī)則如何工作,查看"Handling Layout Changes Automatically Using Autoresizing Rules."
b.如果視圖實現(xiàn)了layoutSubviews方法,UIKit會調(diào)用它。你可以在你的定制視圖中覆蓋這個方法同時用它來調(diào)整任何子視圖的位置和大小。例如,一個提供了巨大滾動區(qū)域的視圖會需要使用幾個子視圖作為“瓦塊”而不是創(chuàng)建一個不太可能放進(jìn)內(nèi)存的巨大視圖。在這個方法的實現(xiàn)中,視圖會隱藏任何屏幕外的子視圖,或者重定位它們?nèi)缓笥脕砝L制新的可視內(nèi)容。作為這個流程的一部分,視圖的布局代碼也可以廢止任何需要被重畫的視圖。

6.如果任何視圖的任何部分被標(biāo)記為需要重畫,UIKit會要求視圖重畫自身。
對于顯式的定義了drawRect:方法的定制視圖,UIKit會調(diào)用這個方法。這方法的實現(xiàn)應(yīng)該盡快重畫視圖的指定區(qū)域,并且不應(yīng)該再做其他事。不要在這個點上做額外的布局,也不要改變應(yīng)用的數(shù)據(jù)模型。提供這個方法僅僅是為了更新視圖的可視內(nèi)容。
標(biāo)準(zhǔn)的系統(tǒng)視圖通常不會實現(xiàn)drawRect:方法,但是也會在這個時候管理它們的繪制。

7.任何已經(jīng)更新的視圖會與應(yīng)用余下的可視內(nèi)容組合在一起,同時被發(fā)送到圖形硬件去顯示。
8.圖形硬件將已解釋內(nèi)容轉(zhuǎn)化到屏幕上。

注意:上面的更新模型主要應(yīng)用于使用標(biāo)準(zhǔn)系統(tǒng)視圖和繪制技術(shù)的應(yīng)用。使用OpenGL ES來繪制的應(yīng)用通常會配置一個單一的全屏視圖和直接繪制相關(guān)的OpenGL圖像上下文。你的視圖還是應(yīng)該處理觸屏事件,但是它是全屏的,毋需給子視圖布局或者實現(xiàn)drawRect:方法。獲取更多關(guān)于使用OpenGL ES的信息,查看 OpenGL ES Programming Guide for iOS.

給定之前的一系列步驟,將自己的定制視圖整合進(jìn)去的方法包括:

事件處理方法:
1.touchesBegan:withEvent:
2.touchesMoved:withEvent:
3.touchesEnded:withEvent:
4.touchesCancelled:withEvent:
5.layoutSubviews方法
6.drawRect:方法

這些是視圖的最常用的覆蓋方法,但是你可能不需要覆蓋全部。如果你使用手勢識別來處理事件,你不需要覆蓋事件處理方法。相似的,如果你的視圖沒有包含子視圖或者它的尺寸不會改變,那就沒有理由去覆蓋layoutSubviews方法。最后,只有當(dāng)視圖內(nèi)容會在運(yùn)行時改變,同時你要用UIKit或者Core Graphics等本地技術(shù)來繪制時才需要用到drawRect。

要記住這些是主要的整合點,但是不僅僅只有這些。UIView類中有些方法是專門設(shè)計來給子類覆蓋的。你應(yīng)該到UIView Class Reference中查看這些方法的描述,以便在定制時清楚哪些方法適合給你覆蓋。

有效使用視圖的提示

當(dāng)你需要繪制一些標(biāo)準(zhǔn)系統(tǒng)視圖不能提供的內(nèi)容時,定制視圖是很有用的。但是你要負(fù)責(zé)保證視圖的性能要足夠的高。UIKit會盡可能的優(yōu)化視圖相關(guān)的行為,也會幫助你提高性能。然而,考慮一些提示可以幫助到UIKit。

重要:在調(diào)整繪制代碼之前,你應(yīng)該一直收集與你視圖當(dāng)前性能有關(guān)的數(shù)據(jù)。估量當(dāng)前性能讓你可以確定是否真的有問題,同時如果真的有問題,它也提供一個基線,讓你在未來的優(yōu)化中可以比較。

視圖不會總是有一個相應(yīng)的視圖控制器
在應(yīng)用中,視圖和視圖控制器之間的一對一關(guān)系是很少見的。視圖控制器的工作是管理一個視圖層次,而視圖層次經(jīng)常是包含了多個視圖,它們都有自包含特性。對于iPhone應(yīng)用,每個視圖層次通常都填滿了整個屏幕,盡管對于iPad應(yīng)用來說不是。

當(dāng)你設(shè)計用戶界面的時候,考慮到視圖控制器的所扮演的角色是很重要的。視圖控制器提供了很多重要的行為,像協(xié)調(diào)視圖的展示,協(xié)調(diào)視圖的剔除,釋放內(nèi)存以響應(yīng)低內(nèi)存警告,還有翻轉(zhuǎn)視圖以響應(yīng)界面的方向變更。逃避這些行為會導(dǎo)致應(yīng)用發(fā)生錯誤。
獲取更多關(guān)于視圖控制器的信息,查看 View Controller Programming Guide for iOS

最小化定制的繪畫

盡管定制的繪畫有時是需要的,但是你也應(yīng)該盡量避免它。真正需要定制繪畫的時候是已有的視圖類無法提供足夠的表現(xiàn)和能力時。任何時候你的內(nèi)容都應(yīng)該可以被組裝到其他視圖,最好結(jié)果時組合那些視圖對象到定制的視圖層次

**利用內(nèi)容模式 **

內(nèi)容模式可以最小化重畫視圖要花費的時間。默認(rèn)的,視圖使用UIViewContentModeScaleToFill 內(nèi)容模式,這個模式會放縮視圖的已有內(nèi)容來填充視圖的frame矩形。需要時你可以改變這個模式來調(diào)整你的內(nèi)容,但是應(yīng)該避免使用UIViewContentModeRedraw內(nèi)容模式。不管哪個內(nèi)容模式發(fā)生作用,你都可以調(diào)用setNeedsDisplay或者setNeedsDisplayInRect:方法來強(qiáng)制視圖重畫它的內(nèi)容。

可能的話將視圖聲明為不透明

UIKit使用opaque屬性來決定它是否可以優(yōu)化組合操作。將一個定制視圖的這個屬性設(shè)置為YES會告訴UIKit不需要解釋任何在該視圖后的內(nèi)容。這樣可以為你的繪制代碼提高性能并且是推薦的。當(dāng)然,如果你將這個屬性設(shè)置為YES,你的視圖一定要用不透明的內(nèi)容完全填充它的bounds矩形。

滾動時調(diào)整視圖的繪制行為

滾動會導(dǎo)致數(shù)個視圖在短時間內(nèi)更新。如果視圖的繪制代碼沒有被適當(dāng)?shù)恼{(diào)整,滾動的性能會非常的緩慢。相對于總是保證視圖內(nèi)容的平庸,我們更傾向于考慮滾動操作開始時改變視圖行為。例如,你可以暫時減少已解釋的內(nèi)容,或者在滾動的時候改變內(nèi)容模式。當(dāng)滾動停止時,你可以將視圖返回到前一狀態(tài),同時需要時更新內(nèi)容。

**不要嵌入子視圖來定制控制 **

盡管在技術(shù)上增加子視圖到標(biāo)準(zhǔn)系統(tǒng)控制對象-繼承自UIControl的類-是可行的,你還是永遠(yuǎn)不應(yīng)該用這種方法來定制它們。控制對象支持定制,它們有顯式并且良好歸檔的接口。例如,UIButton類包含了設(shè)置標(biāo)題和背景圖片的方法。使用已定義好的定制點意味著你的代碼總是會正確的工作。不用這些方法,而嵌入一個定制的圖像視圖或者標(biāo)簽到按鈕中去會導(dǎo)致應(yīng)用出現(xiàn)未預(yù)期的結(jié)果。

以上內(nèi)容 為官方文檔翻譯(來源于網(wǎng)絡(luò)),如果你英文還可以,請看英文地址:英文地址
http://blog.csdn.net/mengtnt/article/details/6716289
UIView的剖析 總結(jié)的不錯

轉(zhuǎn)載自http://www.cnblogs.com/likwo/archive/2011/06/18/2084192.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Core Animation基礎(chǔ) Core Animation 利用了硬件加速和架構(gòu)上的優(yōu)化來實現(xiàn)快速渲染和實時動...
    獨木舟的木閱讀 1,702評論 0 3
  • 天朗氣清,好天氣! 今天學(xué)校正式通知家長們周二考試,各種囑咐,比如要帶鉛筆橡皮直尺一類的,還有家長們的各種擔(dān)心,我...
    王柯媽媽閱讀 273評論 0 0
  • 目錄:1、獲取當(dāng)前設(shè)備類型2、獲取當(dāng)前語言環(huán)境3、獲取當(dāng)前APP版本號 1、獲取當(dāng)前設(shè)備類型 2、獲取當(dāng)前語言環(huán)境...
    PZcoder閱讀 336評論 0 0
  • //獲取現(xiàn)在時間的秒鐘分鐘時鐘數(shù) NSDate * date=[[NSDate alloc]init]; NSDa...
    草莓拿鐵閱讀 342評論 0 1
  • 配色專題 常見問題 整套幻燈片看起來很臟 整套幻燈片顏色太單調(diào) 不懂配色,有些內(nèi)容看不清楚 配色的作用 強(qiáng)化主題 ...
    馬騰Madao閱讀 1,733評論 0 7

友情鏈接更多精彩內(nèi)容