UIStackView 比例布局仅具有内在内容大小

2024-03-12

我在 UIStackView 中排列子视图的布局方面遇到问题,想知道是否有人可以帮助我了解发生了什么。

所以我有 UIStackView 有一些间距(例如 1,但这并不重要)和 .fillProportionally 分布。我添加的排列子视图仅具有 1x1 的内在内容大小(可以是任何东西,只是方形视图),并且我需要它们在 stackView 中按比例拉伸。

问题是,如果我添加没有实际框架而仅具有内在尺寸的视图,那么我会得到错误的布局

否则,如果我添加具有相同大小的框架的视图,一切都会按预期工作,

但我真的不想设置视图的框架。

我很确定这都是关于拥抱和压缩阻力优先级的,但无法弄清楚正确的答案是什么。

这是一个 Playground 示例:

import UIKit
import PlaygroundSupport

class LView: UIView {

    // If comment this and leave only intrinsicContentSize - result is wrong
    convenience init() {
        self.init(frame: CGRect(x: 0, y: 0, width: 1, height: 1))
    }

    // If comment this and leave only convenience init(), then everything works as expected
    public override var intrinsicContentSize: CGSize {
        return CGSize(width: 1, height: 1)
    }
}

let container = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
container.backgroundColor = UIColor.white

let sv = UIStackView()
container.addSubview(sv)


sv.leftAnchor.constraint(equalTo: container.leftAnchor).isActive = true
sv.rightAnchor.constraint(equalTo: container.rightAnchor).isActive = true
sv.topAnchor.constraint(equalTo: container.topAnchor).isActive = true
sv.bottomAnchor.constraint(equalTo: container.bottomAnchor).isActive = true
sv.translatesAutoresizingMaskIntoConstraints = false
sv.spacing = 1
sv.distribution = .fillProportionally

// Adding arranged subviews to stackView, 24 elements with intrinsic size 1x1
for i in 0..<24 {
    let a = LView()
    a.backgroundColor = (i%2 == 0 ? UIColor.red : UIColor.blue)
    sv.addArrangedSubview(a)
}
sv.layoutIfNeeded()

PlaygroundPage.current.liveView = container

这显然是实现中的一个错误UIStackView(即系统错误)。

DonMag已经在他的评论中给出了指向正确方向的提示:

当您设置堆栈视图的spacing为 0,一切都按预期进行。但是当您将其设置为任何其他值时,布局就会中断。


这是原因的解释:

ℹ️ 为了简单起见,我假设堆栈视图有

  • a 横轴 and
  • 10 个排列的子视图

随着.fillProportionally分配UIStackView创建系统约束如下:

  • 对于每个排列的子视图,它添加一个等宽约束(UISV-fill-proportionally)与堆栈视图本身相关乘数:

    arrangedSubview[i].width = multiplier[i] * stackView.width
    

    如果你有n在堆栈视图中排列子视图,你会得到n这些限制。让我们称呼他们为proportionalConstraint[i] (where i表示各个视图在视图中的位置arrangedSubviews array).

  • 这些限制是不需要(即它们的优先级不是 1000)。相反,对第一个元素的约束arrangedSubviews第一个数组的优先级为 999,第二个数组的优先级为 998,依此类推:

    proportionalConstraint[0].priority = 999 
    proportionalConstraint[1].priority = 998 
    proportionalConstraint[2].priority = 997 
    proportionalConstraint[3].priority = 996
    ...         
    proportionalConstraint[n–1].priority = 1000 – n
    

    这意味着所需的约束总是会克服这些比例限制!

  • 为了连接排列的子视图(可能有间距),系统还创建n–1称为约束UISV-spacing:

    arrangedSubview[i].trailing + spacing = arrangedSubview[i+1].leading
    

    这些限制是required(即优先级 = 1000)。

  • (系统还将创建一些其他约束(例如,对于垂直轴以及将第一个和最后一个排列的子视图固定到堆栈视图的边缘),但我不会在这里详细介绍,因为它们与理解什么无关出错了。)

苹果的文档 https://developer.apple.com/documentation/uikit/uistackviewdistribution/1616217-fillproportionally on the .fillProportionally分布状态:

一种布局,其中堆栈视图调整其排列视图的大小,以便它们沿着堆栈视图的轴填充可用空间。视图根据其沿堆栈视图轴的内在内容大小按比例调整大小。

所以根据这个multiplier为了proportionalConstraints 应计算如下for spacing = 0:

  • totalIntrinsicWidth = ∑i intrinsicWidth[i]
  • multiplier[i] = intrinsicWidth[i] / totalIntrinsicWidth

如果我们排列的 10 个子视图都具有相同的固有宽度,则这将按预期工作:

multiplier[i] = 0.1

for all proportionalConstraints。然而,一旦我们将间距更改为非零值,则计算multiplier变得更加复杂,因为必须考虑间距的宽度。我已经完成了数学计算和公式multiplier[i] is:


Example:

对于堆栈视图配置如下:

  • 堆栈视图宽度 = 400
  • stackView.spacing = 2

上面的等式将得出:

multiplier[i] = 0.0955

您可以通过将其相加来证明这是正确的:

(10 * width) + (9 * spacing)
    = (10 * multiplier * stackViewWidth) + (9 * spacing)
    = (10 * 0.0955 * 400) + (9 * 2)
    = (0.955 * 400) + 18
    = 382 + 18
    = 400
    = stackViewWidth

然而,系统分配了不同的值:

multiplier[i] = 0.0917431

总宽度加起来为

(10 * width) + (9 * spacing)
    = (10 * 0.0917431 * 400) + (9 * 2)
    = 384,97
    < stackViewWidth

明显地,这个值是错误的。

因此,系统必须打破约束。当然,它打破了最低优先级的约束,即proportionalConstraint最后排列的子视图项目的。

这就是屏​​幕截图中最后排列的子视图被拉伸的原因。

如果您尝试不同的间距和堆栈视图宽度,您最终会得到各种看起来奇怪的布局。但他们都有一个共同点:间距始终优先。(如果将间距设置为更大的值,例如 30 或 40,您将只能看到前两个或三个排列的子视图,因为其余空间已完全被所需间距占据。)


总结一下:

The .fillProportionally分发仅适用于spacing = 0.

对于其他间距,系统会使用不正确的乘数创建约束。

这打破了布局

  • 如果乘数小于应有的值,则必须拉伸任一排列的子视图(最后一个)
  • 如果乘数大于应有的值,则必须压缩多个排列的子视图。

解决这个问题的唯一方法是“滥用”普通UIView具有所需的固定宽度约束作为视图之间的间距。 (通常情况下,UILayoutGuide为此目的引入了 s,但您甚至不能使用它们,因为您无法将布局指南添加到堆栈视图。)

恐怕由于这个错误,没有干净的解决方案可以做到这一点。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UIStackView 比例布局仅具有内在内容大小 的相关文章

  • Xcode 在 Swift 2.2 和 Swift 3.0 之间切换

    自从我下载了新的 Xcode 并转换 更新了我的语法以来 Xcode 一直在上述 Swift 版本之间随机切换 我在终端中运行了 swift version 它确认 目前 我正在运行 Swift 2 2 我看到这个问题 Swift 编译器混
  • Semaphore.wait(timeout: .now()) 的目的是什么?

    看了一些苹果代码示例 我发现了这一点 func metadataOutput output AVCaptureMetadataOutput didOutput metadataObjects AVMetadataObject from co
  • itunesconnect 应用程序 - 恢复到以前的版本

    我发布了我的应用程序的更新并获得批准 尽管它包含一个严重的本地化错误 大多数用户都得到了错误的语言 但它还是获得了批准 有什么方法可以快速恢复到以前的版本 暂停当前版本的当前下载 或者其他任何可能有助于解决此问题的方法 我几年前确实读过以下
  • 通过 URL 中的 ID 进行 RestKit 关系映射

    假设我有一个 APIusers 1 items返回一个列表items为了userID 为 1 假设API响应如下 items id 1 description Some item 请注意 响应不包含user id用于关系映射 RestKit
  • iOS 11 文件提供程序扩展中的项目

    我有一个带有文件提供程序扩展名的应用程序 我尝试使用此方法为 ios 11 的新文件应用程序提供支持link https developer apple com documentation fileprovider content and
  • 在 UIButton 中垂直显示标题?

    我是 iPhone 编程新手 我被这个简单的问题困扰了 我有一个UIView with a UIButton在里面 维度为UIButton40x200 靠近左边距 我需要在按钮中垂直显示文本 有没有一种方法可以在不使用任何图像的情况下完成此
  • 将应用程序委托定义为常量?

    我正在尝试编写 iPhone 应用程序 但遇到了问题 我已经在类中声明了一个常量作为应用程序委托 define ikub iKubMobileAppDelegate UIApplication sharedApplication deleg
  • 如何在 UIBarButtonItem 上触发高亮效果

    当您点击UIBarButtonItem in a UIToolbar 有白光效果 是否有可能触发一个事件来显示这种效果 我不想按按钮 只应显示效果 我想向用户展示该按钮后面有新内容 感谢您的帮助 这是 highlight png 我不是在开
  • iPhone 相机访问权限?

    我想知道如何访问 iPhone 相机并实时使用它 例如 仅在相机视图上绘图 另一个相关问题 可以显示吗同时 4 个摄像机视图就像 Mac 上的 Photo Booth 一样 您可以使用 AVFoundation 来做到这一点 void in
  • 创建 Android 智能应用横幅

    Android 设备有类似 iOS 6 智能应用横幅的解决方案吗 这是智能应用横幅的代码 从 Chrome 44 Beta 开始 您可以在 Android 版 Chrome 中推送您的应用程序 您网站上的本机应用程序安装横幅 请看下面的答案
  • 如何在类的参数中保留对另一个对象的引用

    我刚开始学习Apple Swift语言 无法理解 如何在类的参数中保留对另一个对象的引用 List my custom class class RecordsList NSObject var listObj List init inout
  • iOS - Xcode 错误:由于系统完整性保护而无法附加到进程

    当我从 XCode 运行按钮运行应用程序共享扩展 然后尝试共享文件时 XCode 经常显示以下错误 有人知道是什么原因造成的吗 错误 由于系统完整性保护 无法附加到进程 系统完整性保护 SIP 又名无根 是 OS X 10 11 中的一项新
  • (响应式)表格宽度不适合 ios safari 上 iframe 内的容器

    我在 iPhone 的 safari 上的 iframe 内渲染表格时遇到问题 这是示例 http jsfiddle net qb86ojms http jsfiddle net qb86ojms 如果您在桌面浏览器 较小的尺寸 或 and
  • 如何生成 iPhone 模拟器构建或 .zip 文件以在 Facebook 中提交以在 iOS 中进行审核

    我向 Facebook 提交 my app ipa 文件 但被 Facebook 拒绝 并向我发送此消息 我们审核团队的注释 iPhone 您能否重新提交以供审核 提供您的 iOS 应用程序的模拟器版本 而不是 ipa 文件 我正在 iOS
  • 在 iOS 上的 PhoneGap 或 Cleaver (Cordova) 中加载远程 html

    我在我的本机 iOS 6 应用程序中使用 Cordova 2 4 组件 Cleaver 和嵌入式视图 到目前为止 我已经成功创建了项目结构 链接了 Cordova 库并设置了 Hello World 应用程序 该应用程序确实可以提供 设备就
  • 由于不支持 URL 类型 http,因此无法打开该文件

    使用 iOS 9 我正在尝试使用NSFileManager s moveItemAtURL do print localURL http localhost 3000 api v1 activities print cacheFile fi
  • UIViewController 中的 Xcode 5.1 UITableView - 自定义 TableViewCell 出口为零

    我有一个 UITableView 作为 UIViewController 中的子视图 我没有使用 UITableViewController 因为我有一些与 tableview 无关的其他内容占据了屏幕的一部分 我正在使用故事板 我将表视图
  • iOS safari 输入插入符号颜色

    我在 iPhone 设备上使用 Safari 时遇到了一个 CSS 小问题 我的搜索输入是蓝色的 当用户关注它时 插入符号几乎看不见 在所有桌面浏览器中 它都有正确的颜色 白色 即使在桌面 Safari 上也是如此 知道如何修复此问题并更改
  • Swift:ViewModel 应该是结构体还是类?

    我正在尝试在我的新项目中使用 MVVM 模式 第一次 我创建了所有的视图模型来构建 但是 当我使用闭包实现异步业务逻辑 例如 fetchDataFromNetwork 时 闭包捕获旧视图模型值 然后更新为该值 不是新的视图模型值 这是操场上
  • 验证 iOS 应用程序时出错

    我正在尝试发布 iOS 应用程序 但是当我尝试验证我的构建时收到以下错误 Nib file Main iPad nib was not found Please ensure the specified file is included i

随机推荐

  • Log4J 1.2 属性配置器 -> Log4J2

    目前 我们的应用程序使用 Log4J 1 2 并使用以下任一方式对其进行配置 File file PropertyConfigurator configure file getAbsolutePath or URL url Property
  • Mailgun:消息“已接受”,但需要很长时间才能送达(或未送达)

    我正在将 Mailgun 用于我维护的网站 通常 Mailgun 工作得很好 但我遇到了一个奇怪的问题 我的脚本调用 HTTP API 使用 Mailgun 发送消息 然后这些消息在我的日志中显示为 已接受 但随后需要很长时间才能 传送 通
  • 获取 HTML 元素中单击位置的文本

    我有一个包含一些文本的 div 元素 当用户单击该 div 内的单词时 我想突出显示该单词 为了做到这一点 我需要知道点击发生在文本中的哪个字符位置 这样我就可以找到附近的空白并在单词周围插入一些格式 找出文本中点击发生的位置是这里的技巧
  • 自动完成后端

    这是一个面试问题 设计一个自动完成的分布式后端 我会回答如下 自动完成是按给定后缀在字典中进行搜索 这本词典可能应该被组织为trie 该词典是根据最常见的查询构建的 但这是另一回事了 现在我假设字典不会经常更改 例如每天一次而不是每毫秒一次
  • 使用断言的最佳实践?

    使用是否存在性能或代码维护问题assert作为标准代码的一部分而不是仅将其用于调试目的 Is assert x gt 0 x is less than zero 比更好或更差 if x lt 0 raise Exception x is l
  • C++ 初始化数组指针

    如何初始化指向文字数组的指针 我希望 grid 指向新分配的 int 数组 1 2 3 int grid new int 3 grid 1 2 3 谢谢 你不能初始化这样就可以动态分配数组 你也不能assign以这种方式到数组 动态或静态
  • 在 OSX 上编译 clisp-2.49:未找到 LIBFFI

    TL DR Even if libffi似乎已安装 configure即使我给它添加 正确的 前缀 脚本也找不到它 这篇文章的最后一部分 是我陷入困境的地方 我仅提供其他信息来解释我如何到达那里 我对这篇长篇文章表示歉意 如果有些内容与您无
  • Git 克隆:“您似乎克隆了一个空存储库”

    我和一些同事一直致力于一个存储在私人 git 存储库中的项目 历史上没有问题 但最近我尝试克隆 遇到了以下问题 Cloning into project warning You appear to have cloned an empty
  • 限制从 Linq 列表中返回的结果数

    我正在使用 Linq EF4 1 从数据库中提取一些结果 并希望将结果限制为 X 个最新结果 其中X是用户设置的数字 有没有办法做到这一点 我目前正在将它们作为List如果这有助于限制结果集 虽然我可以通过循环来限制这一点 直到我点击 X
  • 默认 GNU 链接器脚本名称,以便 VIM 进行语法突出显示

    链接描述文件的常用后缀是什么 以便 VIM 对其使用语法突出显示 好像是 ld 仅据我所知 Vim 没有提供它的语法文件 至少我的没有 7 3 尝试提供下载的内容here http vim 1045645 n5 nabble com Syn
  • 优化内存密集型数据流管道的 GCP 成本

    我们希望降低在 GCP Dataflow 中运行特定 Apache Beam 管道 Python SDK 的成本 我们构建了一个内存密集型 Apache Beam 管道 每个执行器上运行需要大约 8 5 GB RAM 当前正在加载一个大型机
  • C :警告:赋值使指针来自整数而不进行强制转换[默认启用]

    这是我的代码 include
  • Flink TaskManager 超时?

    我正在运行 Flink 应用程序 通过 Yarn 似乎有时任务管理器会随机超时 这是错误 java util concurrent TimeoutException Heartbeat of TaskManager with id some
  • 将日期与 data.table 包一起使用

    我最近发现了 data table 包 现在想知道是否应该替换我的一些 plyr 代码 总而言之 我真的很喜欢plyr 并且我基本上实现了我想要的一切 然而 我的代码运行了一段时间 并且加快速度的前景足以让我运行一些测试 这些测试很快就结束
  • 使用 jQuery 的 Jenkins json REST api 和 CORS 请求

    我正在尝试使用 Jenkins json API 但无法使身份验证正常工作 setup 詹金斯安全 Jenkin s own user database access Matrix gebaseerde beveiliging CORS 通
  • 'Mysql:Class 的未定义方法初始化'

    我的 MySQL 服务器安装一直遇到问题 在断电后变得混乱 配置 运行 OS X 10 6 5 的 Intel i5 Mac已安装红宝石 1 9 2已安装 Rails 3 0 1MySQL 服务器 最终 安装并运行我完全重新安装了MySQL
  • 延迟加载的 React 路由器无论如何都会路由加载

    我一直在尝试使用 React lazy 和 Suspense 在 React 中延迟加载路由 但无论当前路径如何 某些组件都会加载 Feed Profile 和 Settings 请注意 我实际上并不想延迟加载像 MenuAppBar 和
  • TypeError(不可排序类型:int() <= NoneType())

    这是我第一次用 Python 编写代码 需要一些帮助 我正在使用 Python 34 根本无法理解发生了什么 def roll v x input return x v def startGame v 0 while 0 lt v erro
  • 在 Python Sphinx 生成的文档中包含动态内容

    我正在使用 Sphinx 为我的项目生成文档 并在产品安装过程中构建文档 我想在文本和 或代码块中动态包含主机名 我没有在文档中看到任何解释 也没有看到任何包含 shell 命令输出或特定文件中特定行以外的任何内容的工具 有这个功能吗 这里
  • UIStackView 比例布局仅具有内在内容大小

    我在 UIStackView 中排列子视图的布局方面遇到问题 想知道是否有人可以帮助我了解发生了什么 所以我有 UIStackView 有一些间距 例如 1 但这并不重要 和 fillProportionally 分布 我添加的排列子视图仅