如何使用自动布局使正方形视图随其父视图调整大小

9
在我的特定情况下,我有一个视图控制器内部的视图,我添加了以下约束条件:
  • 将前导、后续、顶部和底部边缘设置为0
  • 将倍数设置为底部边缘的2:1
现在,该视图位于视图控制器的上半部分。
在其中,我添加了一个正方形图像视图,我添加了以下约束条件:
  • 从图像视图到父视图进行Ctrl拖动,并添加相等的高度和宽度。
  • 更改宽度和高度的乘数,直到我得到一个完美的正方形。
  • 添加垂直和水平居中的约束条件
我的约束看起来很完美,但是当在模拟器中运行时,我没有得到一个完美的正方形。除此之外,在不同的模拟器屏幕上运行时,图像视图不会被调整大小。
这是我的设置:
  • 启用自动布局和大小类
  • 对于故事板,我使用推断大小
  • 自适应布局设置为任何宽度和高度
  • 我正在尝试为4s、5、6和6+模拟器运行此程序。
我查看了其他stackoverflow帖子,但似乎没有什么起作用。

有一些基本步骤可以做到这一点吗?

enter image description here

编辑:

设置>=10个限制后:

enter image description here

编辑3: 我两次添加了顶部、底部、前导和尾随约束条件,一次是小于等于(priority 1000),另一次是大于等于(priority 800),常量值为90。我不知道为什么底部会从主视图而不是容器视图(绿色的)拉伸到90个点。

enter image description here


2
你应该在想要保持正方形的视图上使用1:1的aspectRatio约束,然后将其高度或宽度仅包含到其父级中,但不是同时包含。 - Mike Pollard
那么只需将宽高比设置为1:1,并将高度或宽度与父视图成比例即可吗?这样做可以得到一个正方形(但太小了),但它不会根据屏幕大小进行调整,在所有屏幕上都是相同的大小。 - Adrian
4个回答

26

你有一个视图需要在保持纵横比的情况下扩展以填充其容器。这是Auto Layout中常见的模式。

技巧是使用两个约束来控制leading/trailing/top/bottom:

  • 低优先级=10

  • 需要优先级的>=10

将它们结合起来,你会有:

  • 纵横比1:1

  • 在父视图中心X/Y

  • 用于Superview的Leading/Trailing/Top/Bottom =10(在750优先级下)

  • 用于Superview的Leading/Trailing/Top/Bottom >=10(在1000优先级下)

UIImageView也有一些需要考虑的事情:

  • UIImageView将具有基于其显示的图像的内在内容大小,因此您需要确保其内容吸附优先级低于您用于=10约束的750优先级。

  • UIImageView.contentMode确定底层图像相对于UIImageView的大小如何调整大小,默认情况下设置为UIViewContentModeScaleToFill


它可以工作,但我有一个问题。在4s上,正方形看起来太小了,我能以某种方式控制它吗?在6和5s屏幕上,尺寸是可以的。 - Adrian
@Adrian 你可以在图像的父视图上使用最小高度约束。例如:height=superview.height*0.5 @ priority 900, height >= 350 @ priority 1000 - Darren
@darren 那个有效,谢谢。我必须引入一个新的限制条件,如Img.height = 0.25 x superview.height@900,以按比例增加图像大小,因为从iPhone 6到6 Plus,图像的大小急剧增长。 - Ammar Mujeeb
如何将所有的 Leading/Trailing/Top/Bottom to Superview 添加到父视图中? - user25

3
container view
----------------------------------------------
|                     |                      |
|                    >=10                    |
|        imageView    |                      |
|        ----------------------------        |
|        |            |             |        |      
|        |            |             |        |
|        |            |             |        |
|        |            |             |        |
|        |            |             |        |
|- >=10 -|---------- 1:1 -----------|- >=10 -|
|        |            |             |        |
|        |            |             |        |
|        |            |             |        |
|        |            |             |        |
|        ----------------------------        |
|                     |                      |
|                    >=10                    |
|                     |                      |
----------------------------------------------

如果需要,您可以使用较低优先级的约束来指定imageView的高度或宽度。


你能告诉我如何设置这些约束条件吗?我只需添加前导、尾随、底部和顶部的约束条件,选择大于或等于,并将常量设置为10,是这样吗? - Adrian
是的,就像你说的那样,然后将1:1的纵横比添加到图像中(使用cntrl+拖动),将图像拖到自身上。 - Danny Bravo
对我来说不起作用。我附上了一张截图以查看它的外观。 - Adrian
你会如何进行程序化翻译?@DannyBravo - user1585121

2
我用这个配置成功了。
1.首先,我添加了中心X约束(忽略中心Y约束,即使它在我的截图中。由于步骤2,它也会破坏)。
2.然后我添加了顶部和底部约束。
3.最后,我添加了一个纵横比约束。
当我对其进行动画处理时,该框正确地按比例缩放为正方形。如果您想要的话,我可以上传测试项目。 enter image description here

1
在代码中,真实存在。注意:奇怪的 CGFloat.greatestFiniteMagnitude 是必要的(或者至少是一些更大的数字),以便其他约束条件能够被识别。享受吧。
extension UIView {
    func constrainAsSquare(container: UIView, multiplier: CGFloat) {
        translatesAutoresizingMaskIntoConstraints = false

        centerXAnchor.constraint(equalTo: container.centerXAnchor).isActive = true
        centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true

        widthAnchor.constraint(equalToConstant: .greatestFiniteMagnitude).activate(with: .defaultLow)

        heightAnchor.constraint(lessThanOrEqualTo: container.heightAnchor, multiplier: multiplier).activate(with: .defaultHigh)
        widthAnchor.constraint(lessThanOrEqualTo: container.widthAnchor, multiplier: multiplier).activate(with: .defaultHigh)

        widthAnchor.constraint(equalTo: heightAnchor).activate(with: .required)
    }
}

extension NSLayoutConstraint {
    @discardableResult
    func activate(with priority: UILayoutPriority) -> NSLayoutConstraint {
        self.priority = priority
        isActive = true
        return self
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接