iPhone開發應用之UIView開發流程下篇
iPhone開發應用中的UIView你了解多少?繼續我們上篇iPhone開發應用之UIView開發流程上篇的內容開始講述。曾經有人這么說過,在iphone里你看到的,摸到的,都是UIView,所以UIView在iphone開發里具有非常重要的作用。
坐標系統轉換矩陣
坐標系統轉換矩陣給改變視圖(或者是它的視圖)提供了一個輕松和簡易的方法。一個仿射轉換是一個數學矩陣,它指定了在坐標系統中的點是怎么被映射到另一個坐標系統中的點。你可以對整個視圖應用仿射轉換,以基于其父視圖來改變視圖的尺寸,位置或者朝向。你也可以在你的繪制代碼中應用仿射轉換,以對已解釋內容的獨立部分實現相同的操控。如何應用仿射轉換是基于這樣的上下文的:
為了修改整個視圖,可以修改視圖transform屬性的仿射轉換值。
為了在視圖中的drawRect:方法中修改內容的指定部分,可以修改與當前圖形上下文相關的仿射轉換。
當你想實現動畫時,通常可以修改視圖的transform屬性值。例如,你可以使用這個屬性來制作一個視圖圍繞中心點翻轉的動畫。你不應該在其父視圖的坐標空間中用這個屬性來永久的改變你的視圖,像修改它的位置和尺寸。對于這種類型的改變,你可以修改視圖的frame矩形。
注意:當修改視圖的transform屬性值時,所有的轉換都是基于視圖的中心點來實現的。
在視圖的drawRect:方法中,你可以使用仿射轉換來定位或者翻轉你想要繪制的項目。相對于在視圖某些部位中修正對象的位置,我們更傾向于相對于一個固定點去創建對象,通常是(0, 0),同時在繪制之前使用轉換來定位對象。這樣的話,如果在視圖中對象的位置改變了,你要做的只是修改轉換矩陣,這樣比為對象重新創建新的位置性能更好開銷更低。你可以通過使用CGContextGetCTM方法來獲取關于圖形上下文的仿射轉換,同時可以用Core Graphics的相關方法在繪制中來設置或者修改這個轉換矩陣。
當前轉換矩陣(CTM)是一個在任何時候都被使用的仿射矩陣。當操控整個視圖的幾何結構時,CTM就是視圖transform屬性的值。在drawRect:方法中,CTM是關于圖形上下文的仿射矩陣。
每個子視圖的坐標系統都是構建在其祖先的坐標系統之上的。所以當你修改一個視圖的transform屬性,這個改變會影響到視圖及其所有的子視圖。然而,這些改變只會影響到屏幕上視圖的最終解釋。因為每個視圖都負責繪制自己的內容和對自己的子視圖進行布局,所以在繪制和布局的過程中它可以忽略父視圖的轉換。
Figure1- 6描述了在解釋的時候,兩個不同的轉換因子是如何在視覺上組合起來的。在視圖的drawRect:方法中,對一個形狀應用一個45度的轉換因子會使該形狀翻轉指定的角度。另外加上一個45度的轉換因子會導致整個形狀翻轉90度。這個形狀對于繪制它的視圖來講仍然只是翻轉了45度,但是視圖自己的轉換讓它看起來像使翻轉了90度。
Figure 1-6 翻轉一個視圖和它的內容
重要:如果一個視圖的transform屬性不是其定義時轉換矩陣,那么視圖的frame屬性是未定義的而且必須被忽略。當對視圖應用轉換時,你必須使用視圖的bounds和center屬性來獲取視圖的位置和尺寸。子視圖的frame矩形仍然是有效的,因為它們與視圖的bounds相關。
獲取更多關于在運行時修改視圖的transform屬性,查看 “Translating, Scaling, and Rotating Views.”獲取更多如何在繪制過程中使用轉換來定位內容,查看 Drawing and Printing Guide for iOS.
點與像素
在iOS中,所有的坐標值和距離都被指定為使用浮點數,其單元值稱為點。點的數量隨著設備的不同而不同,而且彼此不相關。要明白關于點的最主要一點是它們提供了一個繪制用的固定框架。
Table 1-1 列出了不同iOS設備的分辨率(點度量)。前為寬后為長。只要你依照這些屏幕的尺寸來設計用戶界面,你的視圖就回被相應的設備正確顯示。
Table 1-1
每一種使用基于點度量系統的設備都定義了一個用戶坐標空間。這是幾乎在你所有的代碼都會用到的標準坐標空間。例如,當你要操控視圖的幾何結構或者調用Core Graphics方法來繪制內容時會用到點和用戶坐標空間。即使有時用戶坐標空間里的坐標時直接映射到設備屏幕的像素,你還是永遠不應該假設這是永遠不變的。相反,你應該記住:一個點并不一定對應著屏幕上的一個像素
在設備層面,所有由你指定的視圖上的坐標在某些點上必須被轉化成像素。然而,從用戶坐標空間上的點到設備坐標空間上的像素通常由系統來處理。UIKit和Core Graphics都主要使用基于向量的繪制模型,所有的坐標值都被指定為使用點。這樣,如果你用Core Graphics畫了一條曲線,你會用一些值來指定這條曲線,而不管底層屏幕使用怎樣的解決方法。
當你需要處理圖像或者其他基于像素的技術,像OpenGL ES時,iOS會幫你管理這些像素。對于存儲為應用程序的束中的資源的靜態圖像文件,iOS定義了一些約定,可以指定不同像素密度的圖像,也可以在加載圖像時最大限度的適應當前屏幕的解決方案。視圖也提供了關于當前放縮因子的信息,以便你可以適當的調整任何基于像素的繪制代碼來適應有更高級解決方案的屏幕。在不同屏幕的解決方案中處理基于像素內容的技術可以在"Supporting High-Resolution Screens"和"Drawing and Printing Guide for iOS"找到描述。
視圖的運行時交互模型
當用戶和界面進行交互時,或者由代碼程序性的改變一些東西時,一系列復雜的事件就會發生在UIKit的內部來處理這些交互。在這個系列中的某些點,UIKit喚出你的視圖類,同時給它們一個機會去響應程序的行為。理解這些喚出點對于理解視圖在哪里融入系統很重要。Figure 1-7 展示了這些事件的基本序列,從用戶觸屏開始到圖形系統更新屏幕內容來響應結束。同樣的事件序列也會發生在任何程序性啟動的動作。
Figure 1-7 UIKit 與視圖對象進行交互
以下的步驟分解了圖1-7中的事件序列,既解釋了在每一步發生了什么,也解釋了應用如何響應
1、用戶觸屏
2、硬件報告觸摸事件給UIKit框架
3、UIKit框架將觸摸事件打包成UIEvent對象,同時分發給適合的視圖。(對于UIKit框架如何提交事件給視圖的詳細解釋,查看 Event Handing Guide for iOS)
4、視圖中的事件處理代碼可能進行以下的動作來響應:
改變視圖或者其子視圖的屬性(frame, bounds, alpha, 等等)
調用setNeedsLayout方法以標記該視圖(或者它的子視圖)為需要進行布局更新
調用setNeedsDisplay或者setNeedsDisplayInRect:方法以標記該視圖(或者它的子視圖)需要進行重畫
通知一個控制器關于一些數據的更新
當然,哪些事情要做,哪些方法要被調用是由視圖來決定的。
5、如果一個視圖的幾何結構改變了,UIKit會根據以下幾條規則來更新它的子視圖:
a、如果自動重設尺寸的規則在發生作用,UIKit會根據這些規則來調整視圖。獲取更多關于自動重設尺寸規則如何工作,查看
- "Handling Layout Changes Automatically Using Autoresizing Rules."
b、如果視圖實現了layoutSubviews方法,UIKit會調用它。你可以在你的定制視圖中覆蓋這個方法同時用它來調整任何子視圖的位置和大小。例如,一個提供了巨大滾動區域的視圖會需要使用幾個子視圖作為“瓦塊”而不是創建一個不太可能放進內存的巨大視圖。在這個方法的實現中,視圖會隱藏任何屏幕外的子視圖,或者重定位它們然后用來繪制新的可視內容。作為這個流程的一部分,視圖的布局代碼也可以廢止任何需要被重畫的視圖。
6、如果任何視圖的任何部分被標記為需要重畫,UIKit會要求視圖重畫自身。
對于顯式的定義了drawRect:方法的定制視圖,UIKit會調用這個方法。這方法的實現應該盡快重畫視圖的指定區域,并且不應該再做其他事。不要在這個點上做額外的布局,也不要改變應用的數據模型。提供這個方法僅僅是為了更新視圖的可視內容。
標準的系統視圖通常不會實現drawRect:方法,但是也會在這個時候管理它們的繪制。
7、任何已經更新的視圖會與應用余下的可視內容組合在一起,同時被發送到圖形硬件去顯示。
8、圖形硬件將已解釋內容轉化到屏幕上。
注意:上面的更新模型主要應用于使用標準系統視圖和繪制技術的應用。使用OpenGL ES來繪制的應用通常會配置一個單一的全屏視圖和直接繪制相關的OpenGL圖像上下文。你的視圖還是應該處理觸屏事件,但是它是全屏的,毋需給子視圖布局或者實現drawRect:方法。獲取更多關于使用OpenGL ES的信息,查看 OpenGL ES Programming Guide for iOS.
給定之前的一系列步驟,將自己的定制視圖整合進去的方法包括:
事件處理方法:
- touchesBegan:withEvent:
- touchesMoved:withEvent:
- touchesEnded:withEvent:
- touchesCancelled:withEvent:
- layoutSubviews方法
- drawRect:方法
這些是視圖的最常用的覆蓋方法,但是你可能不需要覆蓋全部。如果你使用手勢識別來處理事件,你不需要覆蓋事件處理方法。相似的,如果你的視圖沒有包含子視圖或者它的尺寸不會改變,那就沒有理由去覆蓋layoutSubviews方法。最后,只有當視圖內容會在運行時改變,同時你要用UIKit或者Core Graphics等本地技術來繪制時才需要用到drawRect。
要記住這些是主要的整合點,但是不僅僅只有這些。UIView類中有些方法是專門設計來給子類覆蓋的。你應該到UIView Class Reference中查看這些方法的描述,以便在定制時清楚哪些方法適合給你覆蓋。
有效使用視圖的提示
當你需要繪制一些標準系統視圖不能提供的內容時,定制視圖是很有用的。但是你要負責保證視圖的性能要足夠的高。UIKit會盡可能的優化視圖相關的行為,也會幫助你提高性能。然而,考慮一些提示可以幫助到UIKit。
重要:在調整繪制代碼之前,你應該一直收集與你視圖當前性能有關的數據。估量當前性能讓你可以確定是否真的有問題,同時如果真的有問題,它也提供一個基線,讓你在未來的優化中可以比較。
視圖不會總是有一個相應的視圖控制器
在應用中,視圖和視圖控制器之間的一對一關系是很少見的。視圖控制器的工作是管理一個視圖層次,而視圖層次經常是包含了多個視圖,它們都有自包含特性。對于iPhone應用,每個視圖層次通常都填滿了整個屏幕,盡管對于iPad應用來說不是。
當你設計用戶界面的時候,考慮到視圖控制器的所扮演的角色是很重要的。視圖控制器提供了很多重要的行為,像協調視圖的展示,協調視圖的剔除,釋放內存以響應低內存警告,還有翻轉視圖以響應界面的方向變更。逃避這些行為會導致應用發生錯誤。
獲取更多關于視圖控制器的信息,查看 View Controller Programming Guide for iOS
最小化定制的繪畫
盡管定制的繪畫有時是需要的,但是你也應該盡量避免它。真正需要定制繪畫的時候是已有的視圖類無法提供足夠的表現和能力時。任何時候你的內容都應該可以被組裝到其他視圖,最好結果時組合那些視圖對象到定制的視圖層次
利用內容模式
內容模式可以最小化重畫視圖要花費的時間。默認的,視圖使用UIViewContentModeScaleToFill 內容模式,這個模式會放縮視圖的已有內容來填充視圖的frame矩形。需要時你可以改變這個模式來調整你的內容,但是應該避免使用UIViewContentModeRedraw內容模式。不管哪個內容模式發生作用,你都可以調用setNeedsDisplay或者setNeedsDisplayInRect:方法來強制視圖重畫它的內容。
可能的話將視圖聲明為不透明
UIKit使用opaque屬性來決定它是否可以優化組合操作。將一個定制視圖的這個屬性設置為YES會告訴UIKit不需要解釋任何在該視圖后的內容。這樣可以為你的繪制代碼提高性能并且是推薦的。當然,如果你將這個屬性設置為YES,你的視圖一定要用不透明的內容完全填充它的bounds矩形。
滾動時調整視圖的繪制行為
滾動會導致數個視圖在短時間內更新。如果視圖的繪制代碼沒有被適當的調整,滾動的性能會非常的緩慢。相對于總是保證視圖內容的平庸,我們更傾向于考慮滾動操作開始時改變視圖行為。例如,你可以暫時減少已解釋的內容,或者在滾動的時候改變內容模式。當滾動停止時,你可以將視圖返回到前一狀態,同時需要時更新內容。
不要嵌入子視圖來定制控制
盡管在技術上增加子視圖到標準系統控制對象-繼承自UIControl的類-是可行的,你還是永遠不應該用這種方法來定制它們。控制對象支持定制,它們有顯式并且良好歸檔的接口。例如,UIButton類包含了設置標題和背景圖片的方法。使用已定義好的定制點意味著你的代碼總是會正確的工作。不用這些方法,而嵌入一個定制的圖像視圖或者標簽到按鈕中去會導致應用出現未預期的結果。
小結:關于iPhone開發應用之UIView開發流程 下篇的內容介紹完了,希望本文對你有所幫助!如果你對iphone開發很有興趣的話,請看iphone開發頻道,更多文章可以讓你參考。