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