【翻譯】iOS 視圖的編程指導(一)

本翻譯不是意譯也不是直譯,由於意譯雜糅太多我的理解有時會曲解原文,直譯太硬,英文思路直譯成中文至關怪異。爲保證原意,儘量的直譯下進行意譯。html

翻譯原文地址git

iOS中的視圖編程指導

在iOS中,咱們會使用多個 window 和多個 View 在屏幕上展現你的應用程序內容。Window 自己不會包涵任何的可見內容,但提供了一個基礎容器給咱們應用程序中的 view 使用。View 定義了一部分你想要填入 window 中的內容。舉個例子,你能夠有用於顯示圖片、文本、形狀或者以上內容的組合 view,甚至你還可使用 view 去組織和管理其它 viewgithub

概覽

每個應用程序至少擁有一個 windowview 去展現它的內容。UIKit 框架和其它系統框架預先定義了一些 view 供你去展現你的內容。這些 view 涵蓋了簡單的 button 和文本 lable 甚至是複雜的 view,好比 table viewpicker viewscroll view。在這些預先定義好的 view 中若是沒有提供你想要的 view,你能夠自定義 view 並本身管理繪製和事件處理。編程

view 管理你的應用程序可視內容

一個 viewUIView 類(或者它的一個子類)的實例並管理了一個應用程序 window 中的矩形區域。view 可以進行內容的繪製,處理多點觸控事件和管理該 views 中子視圖的約束。在一個矩形 view 區域中繪圖會涉及到使用圖像技術,好比 Core GraphicsOpenGL ES 或者 UIKit 去繪製形狀、圖片和文本。view 可以直接響應手勢識別或觸摸事件。在 view 的視圖層級中,父視圖負責其子視圖的位置和大小,且還能動態的完成。父視圖的這個動態修改的能力可以讓你的 view 去適應條件的改變,好比說界面旋轉和動畫。數組

你能夠認爲 view 是構建你的用戶界面中的一個磚塊。你會常常的使用一系列的 view 去構建一個等級視圖去展現內容,而不是隻使用一個 view。每個在等級視圖中的 view 都表現了用戶界面中的一部分,而且一般是用於優化一個具體的內容類型,例如,UIKit 有不少個用於優化圖像、文本和其它類型內容的 view緩存

相關章節:View and Window ArchitectureViewsapp

配合 window 顯示你的 view

windowUIWindow 類的實例且可以處理所有呈如今應用程序用戶界面上的內容。window 使用 view(及其視圖控制器)來管理視圖層級的交互和改變。在大部分的時候,你的應用程序 window 並不會發生改變。window 建立以後,它不會發生改變,只有經過它顯示view 纔會發生改變。每個應用程序都至少擁有一個 window 在設備的主屏幕上去顯示這個應用程序的用戶界面。若是有外部顯示設備鏈接到了這個設備,應用程序可以很好的在這個外部顯示設備上建立第二個 window 去呈現內容。框架

相關章節:Windowsiview

動畫提供了用戶可見界面改變的反饋

動畫提供了關於用戶可見視圖層級改變的反饋。系統定義了呈現模態視圖(或單一視圖)和位於不一樣組合視圖之間的標準過渡動畫。可是,view 的許多屬性能夠進行動畫。例如,能夠經過動畫改變 view 的透明度,在屏幕中的位置,大小,背景顏色或者其它的屬性。若是你直接使用底層的 Core Animation 層對象,你可以做出不少不錯的動畫。ide

相關章節:Animations

Interface Builder 扮演的角色

Interface Builder 是一個圖形構造和配置你的應用程序 windowview 的工具。使用Interface Builder 可以把 view 集中在 nib 文件中進行處理,nib 是一個存儲了你能夠自由操控版本的 view 或其它對象資源的文件,當你在 runtime 中加載一個 nib 文件時,你可使用你的代碼去操縱這些位於真實對象中的 view

當你不得不去進行建立應用程序界面的工做時,使用 Interface Builder 會變得很是簡單 。由於在 iOS 中已經整合進了對 Interface Buildernib 的支持,只須要一點時間就能夠把你應用程序的設計工做合併到 nib 中。

關於如何使用 Interface Builder 的其它信息,可查看 Interface Builder User Guide。關於如何使用 view controller 管理包涵這些 viewnib 文件,可查看 View Controller Programming Guide for iOS 中的建立自定義視圖控制器部分。

查看更多

由於視圖是很是複雜和靈活的對象,在一個文檔中徹底講解是很困難的。可是,下面的這些文檔可以很好的幫助你去學習關於如何管理視圖交互和用戶界面的內容。

  • 視圖控制器是管理應用中的視圖很重要的一部分。視圖控制器控制着在其單一視圖層級之中的全部視圖,並協助這些視圖在屏幕上的顯示。查看 View Controller Programming Guide for iOS 來得到更多關於視圖控制器的內容以及它運行規則的信息。
  • 視圖是應用的手勢和觸摸事件的關鍵接收者。查看 Event Handling Guide for iOS 來得到更多關於如何使用手勢識別器和處理觸摸事件。
  • 自定義視圖必需要使用可信賴的繪製技術去渲染其內容。查看 Drawing and Printing Guide for iOS 來得到更多關於使用這些技術去繪製你的視圖內容。
  • 在一些標準視圖動畫沒法知足的部分,你可使用核心動畫庫 Core Animation。查看 Core Animation Programming Guide 來得到更多關於使用核心動畫庫 Core Animation 實現動畫的內容。

viewwindow 的結構

viewwindow 展現應用程序用戶界面和處理界面上的交互。UIKit 和其它系統框架提供了一些只須要作一點修改或徹底不修改就可使用的 view。你還能夠自定義視圖去展現標準視圖不容許的位置內容。

視圖結構的基礎知識

咱們想要經過可視化完成的事情大多都是基於 view 對象的,也就是 UIView 類的實例。view 對象在屏幕上定義了一個矩形區域,該區域可以繪製並和響應觸摸事件。view 可以做爲其它 view 的父容器,管理它們的位置和大小。UIView 類自己管理了這些工做的大部分,但咱們也能夠根據須要自定義視圖之間的默認行爲。

viewCore Animation 層共同處理內容的渲染和動畫。每個 view 都擁有一個 layer 對象(一般是 CALayer 的實例),它負責 view 的渲染內容和與 view 相關的動畫。咱們大多數狀況下的操做應該經過 UIView 提供的接口進行,但在某些須要對渲染或動畫行爲進行更多的控制時,咱們能夠替換爲對 layer 進行操做。

爲了便於咱們理解 viewlayer 的關係,下面這個例子能夠提供幫助。圖 1-1 展現了來自於 ViewTransitions 這個簡單應用的視圖結構和它與底層 Core Animation 層的關係。這個應用程序的視圖包括一個 window(本質上是個 UIView),它是一個繼承於 UIView 類且做爲 view 容器的對象,一個圖像 view,一個用於顯示按鈕的 toolbar 以及一個 bar button item(它不是 view,但其內部有一個可共使用的 view)。(實際上 ViewTransitions 這個簡單應用還包括了一個用於實現變換的圖像 view,但爲了保證簡單,在圖 1-1 中並無描述出來)。每一個 view 都有與之匹配的 layer 對象,能夠經過 viewlayer 屬性來訪問它。(由於 bar buttom item 不是 view,因此你不能直接訪問它的 layerlayer 層對象的背後是 Core Animation 渲染對象,而且最終用於管理硬件緩衝區中顯示在屏幕上的實際字節。

圖 1-1 簡單應用中的視圖結構

使用 Core Animation layer 對象對性能提高有很大的幫助。要儘量的少調用視圖對象的繪製部分代碼,當這部分代碼被調用時,其結果會被 Core Animation 進行緩存,並在將來進行屢次重用。在須要更新視圖時重用渲染出內容的會消耗大量的繪製週期。在動畫中重用這部分緩存的內容是很是重要的,由於這些內容是可被操控的。使用這些緩存的內容會比建立新內容成本小不少。

view 的視圖層級以及管理子視圖

除了提供自身顯示的內容,view 還能夠做爲其它 view 的容器。當一個 view 包含了另一個 view,父子關係就在其之中創建了。在這個父子關係中,子視圖一般被稱爲 subView 父視圖被稱爲 superView。這種關係類型的建立對應用程序的可視化內容和行爲都形成了影響。

看上去子視圖中的內容會遮擋其父視圖的部分或所有內容,當子視圖是非透明時,則其所佔據的區域將會徹底遮擋父視圖。若是子視圖是部分透明的,則父子視圖中的內容會先進行融合再顯示於屏幕上。每一個 superView 都一個存儲 subView 的數組,數組中元素的位置會影響每一個 subview 的可見性。 當同爲一個 superView 的兩個 subView 互相重疊在了一塊兒,最後添加進 superView 中的(或移動到 subView 數組最後的) subView 將會顯示在在上面。

superViewsubView 的關係還影響到了一系列的視圖行爲。改變一個父視圖的大小時會波及到其子視圖的大小和位置。當改變父視圖的大小時,咱們能夠適當的經過一些配置方法來從新設置每一個子視圖大小。例如隱藏父視圖,修改父視圖的透明度或者對父視圖的座標系統作數學變換(3D)等這些事件一樣會影響子視圖。

對視圖層級的排布還意味着應用程序如何響應各類事件。當一個特殊的視圖發生了觸摸,系統當即將這個觸摸信息發送給這個視圖進行處理。可是若是該視圖沒有對這個事件進行單獨處理,則系統將會把該事件對象傳遞給父視圖。若是父視圖一樣沒有處理這個事件,系統將會把該事件繼續傳遞給父視圖,在整個響應鏈上以此類推。

更多關於如何建立視圖層級的內容,可查看 Creating and Managing a View Hierarchy

視圖繪製週期

UIView 類使用了「按需變化」的繪製模型去展現內容。當視圖第一次呈如今屏幕上時,系統要求其進行內容繪製。系統對渲染內容進行快照捕獲而且使用該快照做爲該視圖的視覺呈現。若是你從未對視圖內容進行修改,執行視圖內容繪製的代碼將不會再執行。對視圖進行的大多數操做會重複使用快照圖片替代。若是你對內容進行了修改,須要通知系統視圖已經修改。視圖將會重複進行繪製視圖內容的過程,並捕獲新的圖像內容爲快照。

當你的視圖內容修改時,你沒必要當即重繪這些修改的內容。相反,你可使用 setNeedsDisplaysetNeedsDisplayInRect 方法使視圖內容失效。這些方法將會告訴系統視圖的內容已經修改,而且須要在下個時機中進行重繪。系統將會等待到當前 runloop 結束後才進行初始化任何的繪圖操做。這個延遲給你一個機會去使多個視圖內容失效,從視圖層級中添加或者移除視圖,隱藏視圖,調整視圖大小以及調整視圖位置。你對視圖進行全部修改都會在同一時間進行調整。

注意:修改視圖的幾何形狀並不會自動觸發系統對視圖內容的重繪。視圖的 contentMode 屬性決定了如何解釋視圖的幾何形狀修改。大多數 contentMode 在延伸和重定位已經存在快照的邊界,而不是建立一個新的快照。獲取更多 contentMode 是怎麼影響你的視圖繪製週期的,能夠查看 Content Modes

當渲染視圖內容時,實際的繪製過程的變化會依賴於視圖及其配置。系統視圖通常經過實現私有繪圖方法來完成視圖內容的渲染。這些相同的系統視圖常常會暴露出接口供咱們配置視圖的實際外觀。自定義 UIView 類型的子類,一般你要針對你的視圖去重載 drawRect: 方法去繪製你視圖的內容。這還有一些其它方法提供完成內容的繪製,例如直接設置底層的內容,可是重載 drawRect 方法是目前最經常使用的方法。

獲取更多關於如何繪製自定義視圖的內容,可見 Implementing Your Drawing Code

內容模式(content modes

每一個視圖都有一個內容模式,其控制瞭如何根據視圖的幾何尺寸發生變化時回收視圖內容,以及是否回收視圖內容。當視圖第一次顯示時,按照流程繪製其內容並捕獲其內容於底層位圖中。接下來改變視圖幾何尺寸並不會致使位圖的從新建立。反而,contentMode 屬性目的在於位圖是否縮放以進行適配新的界限,仍是僅簡單的貼在一個視圖的角或者邊上。

視圖的內容模式在你作如下操做時生效:

  • 改變視圖的 framebounds 矩形區域的寬或高。
  • 賦值帶有縮放功能的 transform 變換給視圖的 transform 屬性。

默認狀況下大多數視圖的 contentMode 屬性是 UIViewContentModeScaleToFill,它可以讓視圖內容縮放適配至新的 frame 大小。圖 1-2 展現了一些可用的內容模式結果。從圖中能夠看到,不是全部的內容模式都會徹底充滿視圖界限,而且有一些還會致使視圖內容的失真。

Figure 1-2  Content mode comparisons

內容模式對於視圖回收很是適合,但若是你特別想在縮放或者重設尺寸操做時自定義視圖重繪它,還可使用 UIViewContentModeRedraw 該內容模式。給視圖模式設置爲該值可以當幾何尺寸改變時強制讓系統調用 drawRect: 方法。通常狀況下,應該儘量的避免在任什麼時候候使用該值,除非你很是肯定你不會使用標誌系統視圖。

查看更多關於可用的內容模型內容,可看 UIView Class Reference

可伸縮的視圖

你能夠指定視圖的一部分做爲可伸縮區域,以致於當視圖改變其大小時只修改了可伸縮區域。一般會在按鈕或者其它視圖中使用可伸縮區域,其中視圖的部分區域定義了一個可重複模式。視圖中指定的可伸縮區域容許在單獨一個軸或者兩個軸上進行伸縮。須要注意的是,當對兩個軸進行伸縮,對視圖的邊來講還要定義一個重複模式避免任何變形。圖 1-3 清晰的展現了失真是怎麼在視圖中展現出來的。來自原圖中每個像素點的顏色重複的經過一致的排列充滿了大圖。

Figure 1-3  Stretching the background of a button

使用 contentStretch 屬性指定視圖的可伸縮區域。這個屬性接受一個矩形區域,該值是 0.0 到 1.0 範圍內的標準值。當伸縮視圖時,系統將會對視圖當前的 bounds 值和縮放值與該標準值進行乘積,以達到肯定對視圖一個像素或多個像素的伸縮。使用標準值可以下降當視圖界限改變時更新 contentStretch 屬性值的次數。

視圖的內容模式還扮演瞭如何使用視圖的伸縮區域決定者的角色。當內容模式致使內容區域的縮放時纔會使用可伸縮的區域。這意味着可伸縮視圖只支持 UIViewContentModeScaleToFillUIViewContentModeScaleAspectFitUIViewContentModeScaleAspectFill 內容模式。若是你指定了內容模式對內容進行了貼邊或貼角(所以實際上致使內容並不能縮放),該視圖將會忽略可伸縮區域。

注意:指定背景視圖時,建議建立可伸縮的 UIImage 對象時使用 contentStretch 屬性。可伸縮視圖能夠在 Core Animation Layer 中徹底處理,其一般提供更好的性能。

內置動畫支持

每個視圖後都有一個層對象的好處之一是你能夠對與視圖相關的更改進行動畫化。動畫是向用戶傳遞信息交流的有效方法,在設計應用程時應該一直思考這個問題。許多 UIView 的屬性都是可動畫化的,也就是說支持半自動的從一個值到另一個值。提升這些其中一個可動畫化屬性的性能,咱們只須要作:

  1. 告訴 UIKit 你想要一個高性能動畫。
  2. 改變屬性值。

你能夠對 UIView 對象中執行動畫的屬性以下:

  • frame -- 使用這個屬性可以對視圖位置和大小的改變進行動畫變化。
  • bounds -- 使用這個屬性能對視圖大小的改變進行動畫變化。
  • center -- 使用這個屬性能對視圖位置的改變進行動畫變化。
  • transform -- 使用這個屬性可以對視圖選擇和縮放。
  • alpha -- 使用這個屬性可以修改視圖進行透明度的。
  • backgroundColor -- 使用這個屬性可以修改視圖的背景顏色。
  • contentStrech -- 使用這個屬性可以修改視圖的中心延伸。

從一組視圖變換到另一組視圖是動畫很是重要的一點。一般狀況下會使用視圖控制器經過動畫去管理用戶界面各部分中主要修改的部分。舉個例子,展現從高級別到低級別視圖的過渡信息,一般狀況下會使用導航控制器管理每個成功顯示的視圖數據。甚至你還能夠建立兩個視圖集合之間的動畫過渡來替代視圖控制器。在使用標準控制器動畫達不到你想要的結果時,能夠經過這個方法作到。

除了使用 UIKit 進行動畫的建立外,還可使用 Core Animation layer 完成。降低到圖層級別可以對動畫的時間和屬性進行更多的控制。

查看更多關於若是提高基於視圖的動畫性能可看 Animations。查看更多關於如何使用 Core Animation 建立動畫可看Core Animation Programming GuideCore Animation Cookbook.

後記

歡迎關注 PJ 的 iOS 開發平常

相關文章
相關標籤/搜索