UIStackView使用介紹

在iOS開發中,對於控件佈局我們一般是使用AutoLayout加約束的機制實現,UIKit有一個佈局組件UIStackView,它與Flutter中的Column和Row有點類似,我們可以使用這個控件實現橫向或縱向上子視圖的佈局。

一、如何使用?

首先來了解幾個重要的屬性:
-open var axis: NSLayoutConstraint.Axis
這個屬性有horizontalvertical兩種值,代表橫向佈局還是縱向佈局子控件,默認是horizontal。設定了這個的屬性後,內部的arrangedSubviews不需要添加主軸方向上的約束(指的是vertical時上下和horizontal時左右)。

-open var alignment: UIStackView.Alignment
這個屬性代表內部arrangedSubviews的對齊方式, 默認.fill

public enum Alignment : Int {
        // 橫向stack:貼緊頂部和底部,縱向stack則貼緊頭部尾部
        case fill = 0
        // 橫向stack:頂部對齊,縱向stack:頭部對齊
        case leading = 1
       // 橫向stack:頂部對齊(這是一個計算屬性,返回的是leading)
        public static var top: UIStackView.Alignment { get }
       // 橫向stack下:對齊視圖內文本的第一行基線
        case firstBaseline = 2 // Valid for horizontal axis only
        // 沿着軸線方向居中對齊
        case center = 3
        // 橫向stack:底部對齊,縱向stack:尾部對齊
        case trailing = 4
        // 橫stack:底部對齊(這是一個計算屬性,返回的是trailing)
        public static var bottom: UIStackView.Alignment { get }
        // 橫向stack下:對齊視圖內文本的最後一行基線
        case lastBaseline = 5 // Valid for horizontal axis only
    }

-open var distribution: UIStackView.Distribution
這個屬性代表內部arrangedSubviews的排布方式, 默認.fill。

上面面的解釋中會涉及到約束的硬知識:

  1. 內容擁抱優先級:視圖拒絕變爲大於其固有大小的優先級,優先級越低越容易被拉伸。
  2. 內容壓縮阻力優先級:視圖拒絕小於其固有大小的優先級, 優先級越低越容易被壓縮
nameView1.setContentHuggingPriority(.defaultLow, for: .horizontal)
nameView1.setContentHuggingPriority(.defaultLow, for: .vertical)
nameView1.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
nameView1.setContentCompressionResistancePriority(.defaultHigh, for: .vertical)

如果對內容擁抱優先級(Content Hugging Priority)內容壓縮阻力優先級(Content Compression Resistance Priority)有疑問可查看 iOS開發之AutoLayout中的Content Hugging Priority和 Content Compression Resistance Priority解析

public enum Distribution : Int {
    // 適用於使UIStackView包裹內容,作用是調整內部arrangedSubviews,使它們沿着軸填充UIStackView的剩餘可用空間
    // 1.當內部視圖總體超出UIStackView自身約束的高度/寬度時,
    // UIStackView會根據內部視圖的內容壓縮阻力優先級來收縮,由優先級更低的來收縮;
    // 2.當內部視圖總體不足以排滿UIStackView自身約束的高度/寬度時,
    // UIStackView會根據內部視圖的內容擁抱優先級來擴張,由優先級更低的來擴張;
    // 3. 如果優先級一致時,此時就有歧義,
    // UIStackView會根據索引大小來決定,從索引最小(或者最大,不固定,按照實際開發時看到的情況決定)的view開始收縮或者擴張,直至滿足UIStackView的大小
    // 4.如果UIStackView自身約束的高度/寬度是greaterThanOrEqualTo類型的,UIStackView會根據內容來伸縮。
    case fill = 0
  
    // 適用於需要使內部arrangedSubviews大小一致
    // 使它們沿着軸填充UIStackView的可用空間,子視圖大小相等排布(會忽略Subviews的width和height約束)
    case fillEqually = 1

    // 適用於UIStackView高度/寬度約束固定了,按內部arrangedSubviews寬度高度約束比例來沿着主軸方向排布。
    // 子視圖也需要設置高度/寬度約束,優先級要低於父視圖約束比如:
    // make.height.equalTo(height).priority(900) // 約束優先級默認1000
    case fillProportionally = 2

    // 適用於內部arrangedSubviews之間需要保持相等間隔
    //1. 當內部arrangedSubviews的大小不足以在主軸方向填充UIStackView時,
    // 會將剩餘的空間均分給各個Subview之間間隔排布
    // 2. 當內部arrangedSubviews的大小超出UIStackView時,
    // 會按照內容擁抱優先級來壓縮(沒設置優先級的話,會根據索引從第一個(或者最後一個,按照實際情況)開始壓縮)
    case equalSpacing = 3

    // 1. 當內部arrangedSubviews不足以排滿UIStackView時,
    // 會按照相等的中心距離排布,同時會保持最小的space(由space屬性決定)
    // 2. 當內部arrangedSubviews超出時,會保持最小的space(由space屬性決定),並且根據內容壓縮阻力優先級來壓縮內部視圖;如果優先級未設定,則會間隔一個得壓縮subview
    case equalCentering = 4
}
  • open var spacing: CGFloat
    用來設置arrangedSubview之間的間隔,負值代表重疊;在fillProportionally佈局下是精確的間隔,在equalSpacing,equalCentering佈局下代表最小的間隔。

  • open var isBaselineRelativeArrangement: Bool
    用來設定針對於垂直佈局的view之間的空隙是否以上面視圖最後一行文字的baseline,跟下面view的第一行文字的baseline來判斷。

  • open var isLayoutMarginsRelativeArrangement: Bool
    default is false! 用於設定佈局子view是否使用LayoutMargins

二、中途添加或者刪除內部的view,排列會怎麼樣變化

我們使用UIStackView來佈局內部子view時,子視圖應該以下面方法來添加或者移除. 因爲看方法很直白所以就不解釋用法了,需要注意的是:

  1. 執行了下面方法添加或刪除Subview,內部會重新佈局一次。
  2. 添加的子視圖也會添加到subviews屬性數組中。
open func addArrangedSubview(_ view: UIView)
open func removeArrangedSubview(_ view: UIView)
open func insertArrangedSubview(_ view: UIView, at stackIndex: Int)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章