天天看點

《MonoTouch開發實踐指南》一3.5 實作自定義UIView

對于secondview類,首先要将它設定為uiview的子類,同時添加monotouch.uikit命名空間。要繪制視圖,可以調用drawrect方法。為了給視圖添加自定義繪圖代碼,需要重寫drawrect方法。每一個ios應用程式都有一個主循環。當給drawrect添加代碼時,它在下一次循環時才會調用。不能在程式中直接調用drawrect方法,它隻能由系統在需要的時候調用。當視圖第一次加載的時候,會執行繪圖代碼,是以不需要額外的步驟去調用drawrect。當視圖在初始繪制後,如果要強制重畫,可以調用視圖的setneeddisplay方法,這樣視圖就可以在事件循環過程中進行重畫。

在執行自定義繪圖時,可通過視圖的圖形上下文(graphics context)進行繪制操作。圖形上下文是使用者繪圖用的抽象畫布(如螢幕),可在上面使用任何可用的畫圖工具(如顔色筆、幾何形狀等)進行畫圖。代碼清單3-6列出了部分secondview類用于繪制一個正方形的代碼。

注意 視圖的繪圖工作實際通過層技術實作,這将在第6章進行詳細講述。

代碼清單3-6 自定義繪圖uiview

代碼清單3-6中的繪圖代碼使用了核心圖形(core graphics)功能,這會在第6章講述。也可以在uiview實作中直接使用uikit類。例如,在uiview内使用uilabel顯示視圖的标題,并通過提供标題(title)屬性讓控制器設定标題,代碼如下:

注意 如果不使用uilabel,而是使用核心圖形(core graphics)功能直接繪制标題的字元串,那麼需要在設定标題時調用setneeddisplay方法。盡管在初始化時看不到标題,但調用者會改變視圖的标題。當更改标題時,調用setneedsdisplay方法可以重畫視圖。當更改标題時,uilabel會在内部調用setneedsdisplay方法。

代碼中添加了一個包含标題的uilabel作為子視圖。視圖是按層次結構排列。當添加一個子視圖到一個視圖時,無論是在視圖内部實作(如目前示例的uilabel),還是在外部通過控制器或ib的視圖類實作,按照z次序放置子視圖都會位于其父視圖的上方。如果現在運作應用程式并選擇第二個标簽,将會看到繪制有标題和正方形的螢幕(如圖3-11所示)。

在該示例中,标簽使用了frame屬性和父視圖的bounds對象來設定其大小和位置。frame屬性将視圖的大小設定為一個矩形,它的位置則由父視圖坐标系中的點決定,而邊界則由視圖自己坐标系的大小和位置決定。通常情況下,frame屬性用來設定視圖執行個體的大小和位置,而不是在一個實際的視圖實作中作為邊界使用。例如,在該示例中使用uilabel的執行個體,而不是secondview的實作。在該示例中,父視圖就是secondview。設定uilabel的frame屬性,定義矩形的大小和位置是以父視圖的原點為測量點的。ios坐标系的原點在左上角,往右就是+x,往下就是+y。

注意 在設定視圖的frame屬性時,它實際上并不存儲在視圖内,而是用來從内部獲得其他值,如邊界。同樣,這将在第6章中講述。

視圖要做的另外一件事情就是捕捉事件,如觸碰事件。如果檢查代碼清單3-7中的uiview的類層次結構,就會看到它派生于uiresponder,除此之外,還定義了幾個虛函數用來處理觸碰事件。為了示範這一點,現在在視圖中添加一個簡單的命中測試以檢測使用者是否觸碰了正方形。

代碼清單3-7 uiresponder使用虛函數處理觸碰事件

要判斷是否觸碰了正方形,需要重寫uiview子類的touchesbegan方法,詳細代碼請看代碼清單3-8。為了簡單起見,這裡隻處理單一的觸碰。觸碰點封裝在uitouch類中。要找到視圖的實際觸碰點,可以調用uitouch對象的locationinview方法,它将傳回視圖坐标系内的點。

代碼清單3-8 在uiview子類中處理觸碰事件

之前使用核心圖形的路徑功能來繪制正方形。在路徑中有個containspoint函數可以用來執行命中測試,将uitouch傳回的點傳遞到該函數,它告知點是在路徑組成的正方形内還是在正方形外。然後就可以通過标題将結果輸出給使用者(如圖3-12所示)。

《MonoTouch開發實踐指南》一3.5 實作自定義UIView

繼續閱讀