在 Swift 中剪辑到父视图的子视图

Posted

技术标签:

【中文标题】在 Swift 中剪辑到父视图的子视图【英文标题】:Subview that clips to parent view in Swift 【发布时间】:2020-04-20 08:31:23 【问题描述】:

我正在尝试添加一个始终与其父级大小相同的子视图,以便在父级大小发生变化时始终调整大小。

我正在考虑从代码中添加(顶部、底部、前导、尾随)约束。

当我添加子视图时,执行此代码:

subview.frame = parent.frame
subview.translatesAutoresizingMaskIntoConstraints = false
subview.leadingAnchor.constraint(equalTo: parent.leadingAnchor).isActive = true
subview.trailingAnchor.constraint(equalTo: parent.trailingAnchor).isActive = true
subview.topAnchor.constraint(equalTo: parent.topAnchor).isActive = true
subview.bottomAnchor.constraint(equalTo: parent.bottomAnchor).isActive = true

但子视图大小保持为 0,并显示在屏幕的左上角。 我不明白为什么它的大小为零,因为我设置了它的框架,也因为它具有设置其大小的所有约束。

检查员视图:

注意:父视图在左边,子视图(LoaderView)在右边

【问题讨论】:

这些视图中是否有任何一个滚动视图(我假设是这样,因为我看到消息“可滚动内容大小不明确”)?您的故事板或 xib 中是否有任何自动布局警告?为什么要在情节提要和代码中添加约束?你只需要在一个地方做。最后,如果您使用自动布局,则无需担心设置子视图框架。 @Rob 感谢您的回答。我没有在情节提要中添加约束,因为我以编程方式添加了子视图。是的,你是对的,我不需要设置框架 @Rob 这些是视图层级调试器的屏幕截图——我最初以为它们也是故事板的屏幕截图,呵呵。 【参考方案1】:

您的父视图似乎是一个滚动视图,并且它缺少告诉它其可滚动内容大小是多少的约束(请注意第一个屏幕截图中的警告)。由于没有定义内容大小,因此可滚动区域大小为零。

我不确定您需要什么约束,这取决于您的具体情况,但为了至少看到您的子视图,您可以向子视图添加(例如)等宽和等高约束及其父视图(滚动视图):

NSLayoutConstraint.activate([
    subview.widthAnchor.constraint(equalTo: parent.widthAnchor),
    subview.heightAnchor.constraint(equalTo: parent.heightAnchor)
])

这将可滚动区域定义为与滚动视图的框架在宽度和高度上相等。但是,如果您这样做,那么当您尝试滚动超出可滚动区域时(如果此滚动视图已启用该功能),除了弹跳行为之外,实际上不会有任何类型的滚动。

您可以改为将高度锚点更改为等于某个常数,以允许实际滚动:

NSLayoutConstraint.activate([
    subview.widthAnchor.constraint(equalTo: parent.widthAnchor),
    subview.heightAnchor.constraint(equalToConstant: 2000) // just some arbitrary amount for demonstration purposes
])

这使得可滚动高度等于 2000 磅,而与滚动视图框架的高度无关。

或者,如果您希望可滚动区域是滚动视图框架高度的倍数,您可以在高度锚点上设置一个乘数:

NSLayoutConstraint.activate([
    subview.widthAnchor.constraint(equalTo: parent.widthAnchor),
    subview.heightAnchor.constraint(equalTo: parent.heightAnchor, multiplier: 3)
])

这使得可滚动高度等于滚动视图框架高度的三倍。

如果你想要一个水平滚动的滚动视图,只需像我上面所做的那样更改widthAnchor 而不是heightAnchor。或者,如果您想要一个 2D 可滚动区域,让您可以在垂直和水平方向上进行平移,然后更改两者。

【讨论】:

非常感谢,它完美运行!但是我仍然觉得奇怪的是它适用于宽度和高度约束,但不适用于底部/尾随?我明白了,因为它是一个可滚动的视图,所以没有定义高度和宽度,但是为什么它与宽度约束一起工作呢?或者我错过了什么? 你需要告诉滚动视图它有多大的可滚动区域。仅仅给您的子视图顶部、前导、底部和尾随约束(它们被约束到 可滚动区域,而不是滚动视图的 frame)是不够的——理解差异),因为这些约束本身并不能为滚动视图提供足够的信息来确定可滚动区域的宽度和高度。希望这是有道理的! 谢谢!这个想法是我想在加载其内容时在集合视图的顶部显示一个自定义加载视图;)

以上是关于在 Swift 中剪辑到父视图的子视图的主要内容,如果未能解决你的问题,请参考以下文章

Swift - 将数据从子视图传递到父视图

从子视图中的路径对象在 UIView 中构建剪辑区域

子视图约束到父视图 iOS

在 Cocoa,UIResponder 中将消息从子视图发送到父视图?

SwiftUI 绑定到父视图重新渲染子视图

无法关闭在 Interface Builder 中创建的 NSView 实例的剪辑