UIStackView使用介绍

在iOS开发中,对于控件布局我们一般是使用AutoLayout加约束的机制实现,UIKit有一个布局组件UIStackView,它与Flutter中的Column和Row有点类似,我们可以使用这个控件实现横向或纵向上子视图的布局,好处是它本身不参与渲染,坏处是相对UIView有学习理解成本。

一、如何使用?

首先来了解几个重要的属性:
-open var axis: NSLayoutConstraint.Axis
这个属性有horizontalvertical两种值,代表横向布局还是纵向布局子控件,默认是horizontal。设定了这个的属性后,内部的arrangedSubviews不需要添加主轴方向上的约束(指的是vertical时上下和horizontal时左右)。

-open var alignment: UIStackView.Alignment
这个属性代表内部arrangedSubviews的对齐方式, 默认.fill

文字对齐情况.png

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. 内容拥抱优先级(Content Hugging Priority):视图拒绝变为大于其固有大小的优先级,优先级越低越容易被拉伸。
  2. 内容压缩阻力优先级(Content Compression Resistance Priority):视图拒绝小于其固有大小的优先级, 优先级越低越容易被压缩
nameView1.setContentHuggingPriority(.defaultLow, for: .horizontal)
nameView1.setContentHuggingPriority(.defaultLow, for: .vertical)
nameView1.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
nameView1.setContentCompressionResistancePriority(.defaultHigh, for: .vertical)

如果对内容拥抱优先级内容压缩阻力优先级有疑问可查看 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
    default is false! 用于纵向布局的stackView,用来设定垂直布局的view之间的空隙是否以上面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)
三、我的代码我的坑
1. 背景色

iOS 14以下,设置背景色是失效的,iOS14及以上可以设置背景色。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容