你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 使用Auto Layout處理比例間距問題

使用Auto Layout處理比例間距問題

編輯:IOS開發基礎

36.jpg

  • 本文由CocoaChina--小蘋果程序員(論壇ID)翻譯

  • 作者:@kharrison

  • 原文:Proportional Spacing with Auto Layout


Auto Layout 是一個掌握起來很具有挑戰性的東西。iOS 9引入的 Stack Views 和 layout 錨點有一些幫助,但是明白如何創建特定的 layout仍有一定難度。 

在這篇文章中我想著眼於一個經常出現的情形: 你需要沿一個軸向按固定比例放置視圖。可能並不是十分明顯, 但是這個需求可以通過 一個multiplier中心對齊來輕松實現,它是一種在有無Stack Views情況下都可以使用的技術。

問題

設想我們要構建這樣一個布局,上面有兩排圖片視圖,都是基於父視圖寬度和高度的某一百分比放置。之所以使用圖片視圖, 是因為如果意外地把它們拉伸或壓縮了, 可以十分明顯得看出來。 

2016-01-24-001.png

當視圖適應不同的屏幕大小時, layout 會保持相同的比例。下面是同一個視圖在橫屏模式下的情形:

2016-01-24-003.png

一旦你看出來我們是基於視圖中心進行對齊的,你就會發現我們可以只使用中心對齊約束來創建整個布局。對每個imageView,我們需要一對約束來確定其在X軸和Y軸的位置,一般的格式是這樣的:

imageView.CenterX = view.CenterX * modifier
imageView.CenterY = view.CenterY * modifier

modifier參數將imageView放置在父視圖尺寸的某個百分比的位置上,如下所示:

2016-01-24-002.png

寓教於樂。這裡有三種方式來創建該布局,第一是使用 IB, 第二是用代碼添加約束,第三是使用 stack view.

使用Interface Builder創建約束

對每個 image view 我們需要添加兩個約束。使用文檔大綱工具欄或者直接在視圖畫布中按住 control 鍵從 image view 中拖拽到父視圖上。每一個都添加一個“Center Horizontally in Container”和“Certer Vertically in Container”約束。

2016-01-24-004.png

現在, 編輯每個約束來設置我們需要的百分比例。下面是左上角的紅心圖片視圖的水平和垂直約束設置:

QQ截圖20160318111936.png

注意這也是給我們的約束添加identifiers 的好時機。完成後,你應該添加了10個約束,如下所示:

2016-01-24-007.png

以代碼形式創建約束

在看添加約束的代碼之前,我要提下一個常見的錯誤,當使用代碼添加視圖時, 你需要關閉視圖的 autoresizing mask 向 constraints 的轉變。如果不這樣做,系統會自動創建約束,這會和我們創建的約束發生沖突。

//...code to create image view...
imageView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageView)

有幾種創建這些約束的方法,我將會在視圖控制器的 viewDidLoad 方法中創建. 一個簡單的輔助函數會使創建每個 NSLayoutConstraint 的過程不那麼麻煩:

func addConstraintFromView(subview: UIView?,
                         attribute: NSLayoutAttribute,
                        multiplier: CGFloat,
                        identifier: String) {
  if let subview = subview {
    let constraint = NSLayoutConstraint(item: subview,
            attribute: attribute,
            relatedBy: .Equal,
            toItem: view,
            attribute: attribute,
            multiplier: multiplier,
            constant: 0)
    constraint.identifier = identifier
    view.addConstraint(constraint)
  }
  
}

這樣就可以創建並添加一個相對於父視圖的約束 (使用視圖控制器的 view 屬性)。NSLayoutAttribute 參數在水平約束中為 .CenterX,在豎直約束中為 .CenterY。例如,下面是上面一行的紅心圖片視圖的約束:

// vertical constraint
addConstraintFromView(heartTop,
              attribute: .CenterY,
             multiplier: 0.667,
             identifier: "heartTop center Y")
             
// horizontal constraint
addConstraintFromView(heartTop,
              attribute: .CenterX,
             multiplier: 0.5,
             identifier: "heartTop center X")

剩下的和這個類似,全部設置見示例代碼。

使用Stack View呢?

無論何時只要你遇到水平或垂直布局的問題,你就要想到 stack view。向 stack view 中添加 image views 是很簡單的,但是如何配置呢? 我們不想讓stack view中堆滿views, 所以 Axis 選擇水平軸向, 使用“Equal Spacing”分布方式:

2016-01-24-009.png

現在我們需要約束 stack view 的大小和位置:

  • 使用和設置圖片視圖豎直位置相同的方式設置每個 stack view 的豎直位置。使用modifier中心約束 (例如頂部 stack view 使用 stackView.centerY = 0.667 * superview.centerY 約束)。

  • 向每個 stack view 添加一個水平居中的約束。

  • 最後的約束需要一點小小的技巧,我們需要確定 stack view 的寬度,使用 stack view 的 leading 和 trailing 邊緣是最簡單的方式:

QQ截圖20160318112214.png

左上的 image view 的中心應該是父視圖中心的 0.5 倍. 那麼我們需要 stack view 的左邊向左移動image view 寬度的一半. image view 大小時 100x100, 所以我們需要在約束中減去 50:

2016-01-24-010.png

注意在 IB 中添加這個約束時你需要改變第二項為 superview center,equal spacing 分布方式將會為我們修正 trailing 位置. 用類似的方法處理下方的 stack view,於是我們最終結果如下:

2016-01-24-011.png

這是我發現的一種用代碼添加約束要比在IB中編輯簡單得多的一種情形,尤其是當我們可以在運行時計算 image view 的大小時。

2016-01-31 更新: 還有一個更簡單的方法,為最左邊圖片的中心添加一個約束,stack view 會改變大小來適應,而不需要計算圖片的大小。詳見代碼。

補充閱讀

你可以在 GitHub CodeExamples 上找到這篇帖子的代碼,它包含IB、代碼和 stack view 三個版本,你可以比較下這幾個方法。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved