IOS開發入門(6)-自動佈局(1)

這些截取自《IOS開發完全上手》+部分自己的見解

PS:感覺有些概念問題還是要了解一點的

自動佈局前言

  iPhone和iPod touch設備上的應用程序可以縱向或橫向顯示內容,並且設備配有3.5英寸或4英寸顯示屏。這導致4中不同的佈局:兩種不同小屏幕尺寸下的縱向和橫向佈局。

  即使使用Visual編輯器(可視化編輯器),創建支持4中不同佈局的應用程序也是一項挑戰,尤其是當有動態的屏幕元素時,甚至當語言變化時也會使用不同長度的標籤。其結果可能是大量的定製代碼,以及針對故事版上同一界面的多個視圖控制器

  自動佈局是基於約束的引擎,可以讓你描述視圖之間的關係。自動佈局接收這些描述或約束,並計算出如何跟當前屏幕大小和方向放置應用程序視圖並確定其大小。有了它,就可以爲一個界面只創建一個視圖控制器並且掌控代碼。

  在接下來的幾個小節裏面,將會介紹如何將自動佈局納入應用程序的設計和開發過程中。將首先探索自動佈局的關鍵概念,並利用它們爲Add/View場景設計約束。接下來,通過修改Add/View界面來使之能工作在全部兩種屏幕尺寸的縱向屏幕上。可以使用實用的設計、佈局和調試技巧實現這一點。最後,你會創建自己的約束並藉助動態更新控制器約束的功能來增加對橫向屏幕的支持

自動佈局的基本知識

  當只有一種方向的一種屏幕尺寸時,設計場景時指確定哪些視圖元素是需要的,然後將這些元素放置在視圖中,或放置在視圖層次結構裏。添加旋轉功能會增加複雜性,但扔然是可控的。而一旦除了添加界面方向之外還增加不同的屏幕尺寸,事情就會變得更加複雜。早期版本的IOS提供了一些靈活性,讓你指定當視圖的容器改變大小時,它們如何自我調整。但通常,具有視圖依賴性或稍微複雜的視圖層次的佈局需要編寫代碼。往往這些代碼需要做複雜計算,並且更新許多視圖。

  例如,考慮在不同高度的縱向屏幕上運行應用程序。我們需要知道高度差,哪兒個視圖可以移動/或調整打下,以及它們可以移動和/或調整大小到多大程度。然後,我們需要選擇哪兒個視圖來實際地移動和/或調整大小。如果高度差異要求移動多少個視圖,那麼我們很可能需要編寫代碼。

  縱向和橫向之間的旋轉更加複雜。問題也更大。

  例如,前面幾節做的CarValet,我們做個旋轉,然後變成這個樣子。

這裏寫圖片描述

  可以自己試試看。想一下,將設備旋轉爲橫向,然後再恢復的過程中,單個視圖元素如何移動。注意發生了多少起移動。可以看到,在不斷變化的環境中發生了很多事情。每個視圖都經過多個步驟。儘管中間步驟已經自動爲我們做好,但最好想象一下計算每個視圖的最終位置和大小。可能有太多的重新計算,使得這樣做不如創建一種不同的佈局。

  現在假設我們的佈局是4英寸的屏幕創建,我們現在要檢測3.5英寸的屏幕,計算出大小差異,移動按鈕並調整汽車信息標籤。實現這一種變化的一些僞代碼如下:

if (!is4InchDisplay && (deltaHeight > 0.0) {
    carInfoLabel.frame.size.height = deltaHeight / 2.0;
    previousButton.frame.origin.y -= deltaHeight;
    editButton.frame.origin.y -= deltaHeight;
    nextButton.frame.origin.y -= deltaHeight;
}

  這並不是有效的Objective-C代碼,真實代碼會更長。即使是僞代碼,也爲這個簡單的實例做了很多工作,而且目前並不容易清楚這些代碼的作用。更糟的是,對可視化佈局的所有變更都要求修改代碼。

  對我們來說,描述視圖之間如何關聯,或再當前這種情況下視圖分組之間如何關聯,是更容易的。以下使用三個視圖分組:添加汽車視圖分組包含汽車總數標籤和增加汽車按鈕,分隔符視圖只包含本身,而查看汽車視圖分組中包含其餘的元素。

  • 添加汽車視圖分組的高度是固定的,該高度是指它距離容器頂部的iOS標準距離
  • 分隔符視圖到它的容器的頂部有固定的距離,並且有固定的高度
  • 查看汽車視圖分組到容器視圖的底部和兩側爲標準距離,而頂部到分割符視圖爲固定距離

      這些描述創建可以根據屏幕高度增大或縮小的查看汽車視圖分組。“標準距離”指的是蘋果公司建議的內凹和空間。由於查看汽車視圖分組可以變化,因此需要制定組成視圖之間加何關聯。Car Info標籤距離頂部和底部有足夠的空白,可以根據屏幕搞懂調整大小:

  • Car Number標籤固定到其容器視圖(查看汽車視圖分組)的頂部

  • 每個按鈕都固定到其容器視圖的底部
  • Car Info標籤的頂部到Car Number標籤的底部爲標準距離,而底部到Previous按鈕的頂部爲標準距離

      當查看汽車視圖分組增大或縮小時,Car Number標籤和按鈕保持固定。Car Info標籤會根據需要來改變高度。使用其他一些描述,可以指定整個場景。

      有了自動佈局,可以創建這些類型的描述,iOS會用它們來弄清楚如何根據當前屏幕大小放置視圖以及調整視圖大小。系統需要解決讓界面適配不同屏幕高度和方向的問題。我們設置可以強制系統重新計算,例如在視圖被擴展或插入時。

      關係是關於用戶界面(UI)元素的一個屬性如何關聯到另一UI元素的屬性的約束。表達兩個視圖之前的所有關係需要一個以上的約束。對於自動佈局的全部功能,只有一些新的方法和類NSLayoutConstraint用於描述這些約束。

約束

  之前介紹的描述是關於視圖間關係的約束。有時關係包含在同一視圖內,有時在相鄰視圖之間,有時在視圖與其容器之間。甚至可以指定不同容器中視圖之間的關係。例如,可以說New Car按鈕與Previous按鈕具有相同的寬度。

像素和點

  查看約束之前,理解像素和點之間的區別是很重要的。像素是屏幕上可用於顯示的單獨彩色元素的物理硬件可尋址組件。它們決定了屏幕的分辨率,以及在給定區域的像素數或像素密度,決定物體在屏幕顯示的銳利程度。

  到目前爲止,iOS單位配備了兩種像素密度,分別針對正常屏幕和Retina顯示屏。因爲Retina顯示屏有兩倍的像素密度,會出現像素在正常顯示屏上正確顯示,但在Retina顯示屏上只有一半大小的情況。正確放置其他屏幕元素時(比如視圖)也會遇到類似的問題,況且將來會有許多不同的像素密度的屏幕。編寫代碼來處理所有可能情況將花費很大工夫。

  相反,蘋果公司使用點——在屏幕繪圖區域內的一種像素無關的表示。它們能夠處理所有的困難工作。屏幕上的座標、元素之間的距離、約束的值都以點了表示,而不是像素;而且圖像可以提供正常屏幕和Retina顯示屏兩種版本。

約束關係

  最簡單一種約束與視圖本身的特性相關,如44點的固定高度。可以用如下方程表達這種約束

view1.height == 44.0

  更常見的是一個視圖的屬性與另一個視圖的屬性之間的關係,例如視圖1的頂部與視圖2的底部的位置是相同的:

View1.top == View2.bottom

  仔細看看這兩種約束關係。它們沒有使用賦值運算符=,而是使用相等運算符==。這是約束的重要組成部分。它們不是賦值。系統可以通過改變語句的某一側或兩側來找到解決方案。例如,在上面的關係中,系統可以改變視圖1的頂部和視圖2的底部。稍後將看到,這是一種構建自適應界面的強大方式,尤其是在百奧名哪兒些約束必須滿足以及系統可以改變這些約束的相對次序時。

  約束定義一個視圖中的屬性如何關聯到另一個視圖中的屬性。屬性是描述視圖幾何結構的方式,幾何結構包括以下內容:

  • 視圖的leading邊緣好trailing邊緣
  • 視圖的left、right、top、bottom邊緣
  • 視圖的width和height
  • centerX和centerY,表示視圖的X和Y中心
  • 視圖的極限。

      以下是約束方程的常見形式:

view1.attribute == (view2.attribute * scaleFactor) + offset

  view1.attribute和view2.attribute是兩個視圖及其屬性,scaleFactor是第二個值要使用的比例,而offset是加到關係上的一個常數。例如,上面的關係1有兩個約束。第一個約束指定視圖的高度。假設高度是102點,這是約束方程:

addCarView.height == 102.0

  請注意,在這個關係中並不需要其他試圖,因此比例因子的有效值是0

  使用比例因子的一個示例是倍增視圖的寬度:
  
  someView.width == someView.width * 2.0

  在本例中,偏移量爲0

  最後,關係必必相等。也可以是以下情況之一:

  • 小於或等於
  • 大於或等於

      例如,如果想爲Car Info標籤設置最小高度,可以用下面僞代碼表示:

carInfoLabel.height >= MinimumHeightForContent

  這個公式是一種理解如何指定約束的方法。儘管可以執行方法調用使整個公式中的所有元素創建約束,但這是最難以實現的辦法。

創建約束

  我們現在已經知道約束是什麼了,可以用一下三種方式創建它們:

  • 使用IB(Interface Builder,用戶界面生成器)
  • 使用VCL(Visual Constant Language,可視化約束語言)
  • 指定關係方程中的所有部分

      用IB創建約束所需做的工作最少,VCL需要做更多的工作,而定義關係方程式則需要做最多的工作。甚至可以讓IB自動創建佈局所需要的最少約束,但是你很可能需要修改。接下來我們將介紹如何使用IB創建約束

使用IB創建約束

  瞭解IB中如何創建約束的最好方法是自己添加一些視圖。爲此,在Xcode中創建新的名爲LayoutTest的單視圖應用程序。介紹個組合件Cmd+Shift+N

  首先將Use Auto Layout取消掉,然後添加Label到圖中位置,注意我們現在用的是iPhone7
這裏寫圖片描述

運行如圖:

iPhone7 iPhone5

  顏色都是白的就不要在意這些細節了…我想說的是用iPhone 5運行的時候,Label竟然不見了。不過我們要說服自己其實Label是在的,現在我們使用IB將頂部座標修改爲488.這時候在運行的話就能看到Label了。

change after

像素保真幫助(Pixel-Perfect Help)

  故事面板被設置爲使用自動佈局呢,會變得怎麼樣?Xcode只是在做我們要求它做的事情而已。通過將標籤按照指定的寬度和高度放在指定位置,告訴Xcode那就是你想將UI元素的放置到的位置。設備有多大或屏幕處於哪個方向並不重要了。
  

  爲確保元素顯示出來的效果正是我們所想要的,編譯器會生成適當的約束。當開始添加自己的約束時,這些約束會優先。也就是說,編譯器不會產生任何佔位符約束以覆蓋我們的約束。 

  我們可能認爲這是沒有幫助的,但實際上它就是我們所想要的效果。知道在我們制定其他位置之前,確保元素是像素完美的,這樣就可以快速地爲佈局創建原型並輕易嘗試約束的組合。

  要理解這一點,需要添加標籤與其容器底部之間距離的約束。爲此,可以選擇標籤,(然後選擇Editor|Pin|Bottom Space to Superivew 這是對於Xcode7之前的版本的,博主的版本沒有,怎麼辦呢,看下圖)

先選中1,點擊2就會出現了
這裏寫圖片描述

  然後做如下修改:
記得點擊Add 2 Constraints
然後運行之後,變成下面的樣子了

change after

添加兩個約束練練手

示例1:

  添加一個UILabel扔到屏幕上並命名爲Center Y

  修改如圖:
  
  你會發現,效果變成下面的樣子

這裏寫圖片描述

  我們再添加一個標籤Top Label

  約束如圖

這裏寫圖片描述

注意圓圈部分點開三角形,選中Use Standard Value,然後點擊添加

改變約束值

  使用工具欄約束彈出窗口(就是上面我們用的那個窗口)是添加約束和任何常數(如距離容器或視圖之間的標準距離)的很好辦法。但是當前需要改變這些值時會發生什麼?

  一種方法是選中這個視圖並打開Size檢查器,這可以通過選擇Center Y進行嘗試。Size檢查器向你顯示所有相互關聯的約束列表。在每個約束的右側是一個edit,他可以讓我們編輯。

例如下圖
這裏寫圖片描述

  可以自己嘗試的更改一下看看發生了什麼變化。然後在旋轉一下看看是不是管用。

  除了編輯約束,還可以使用細節來驗證約束確實對當前屏幕和旋轉方向提供了正確的元素定位。視圖之間的距離以及邊緣排列還可以使用Option鍵來顯示。Option使用方法,點擊你想看的標籤,選中後按下option按鈕,就能顯示了。

這是因爲Option鍵可以顯示當前鼠標指引下的視圖與被選中的視圖之間的距離。

拖拽出約束

  在IB中指定約束的最後一種方法是按住Ctrl鍵從駛入拖動(或用鼠標右鍵拖動)。當結束拖動時,會跳出一個窗口。看圖說的清楚一些

這裏寫圖片描述

  我先讓Label與Center Y有個Top約束,所以Top前面會有白點。其餘情況與之類似。這就是跳出的窗口。

  今天的介紹就到這裏咯

  我的另一個博客站點:Arnold-你們好啊

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章