自动布局:UIImageView 和 Aspect Fit 内容模式

4
我正在尝试将一个 UIImageView 放置在父视图的中心。图像必须保持其原始宽高比,同时不应超出父视图的边界。因此,横向图像应受父视图宽度的限制,纵向图像应占用所需的垂直空间,保持原始比例。听起来对于 AutoLayout 来说是非常简单的任务,对吧?以下是我为 UIImageView 设定的设置:
  • 在父视图中垂直居中
  • 在父视图中水平居中
  • imageView.width <= superview.width
  • imageView.height <= superview.height
我还将contentMode设置为Aspect Fit。对于小于设备屏幕的小图像,一切都运行得非常好,但由于某种原因,对于大图像,我的 UIImageView 占用的空间比其底层的 UIImage 更多(注意绿色背景-imageView.backgroundColor = [UIColor greenColor])。

enter image description here

为什么会这样?虽然我不是AutoLayout专家,但我的约束条件看起来很合理。如果我使用像200x400这样的较小图像,则UIImageView在屏幕上正好占用200x400个点,没有额外的绿色区域。
我想添加边框和圆角,但显然在这种情况下无法正常工作。
2个回答

3
这是因为您将宽度和高度的限制设置为<=。对于小图片,imageView的框架可以计算而没有任何问题,并且所有约束都得到满足。但是当设置大图像时,imageView的大小要根据图像适合的情况进行设置,但同时也受到父视图(屏幕尺寸)的大小限制。
  • 如果您确定宽高比,可以将其设置为约束条件,这样就不会看到任何绿色背景。
  • 否则,请按原样保留您的约束条件,并将背景颜色设置为透明颜色。这样,任何未占用的区域将是透明的,并且您设置的任何图像都将以至少一个维度占用最大空间。

编辑:

可能不是最好的解决方案,有点老式。您可以添加严格的宽度和高度约束,并使用图像的宽高比手动计算它们:

@IBOutlet weak var heightConstraint: NSLayoutConstraint!
@IBOutlet weak var widthConstraint: NSLayoutConstraint!

func setImage(image: UIImage) {
    imageView.image = image
    let screenSize = UIScreen.main.bounds.size

    let imageAspectRatio = image.size.width / image.size.height
    let screenAspectRatio = screenSize.width / screenSize.height

    if imageAspectRatio > screenAspectRatio {
        widthConstraint.constant = min(image.size.width, screenSize.width)
        heightConstraint.constant = widthConstraint.constant / imageAspectRatio
    }
    else {
        heightConstraint.constant = min(image.size.height, screenSize.height)
        widthConstraint.constant = heightConstraint.constant * imageAspectRatio
    }
    view.layoutIfNeeded()
}

很不幸,我无法预先知道纵横比,因为我需要在此视图中显示不同的图像:大图、小图、横向、纵向甚至正方形。屏幕截图中的图像分辨率为3264x2448,实际上已经适当缩小:它保持了其比例,没有被截断或扭曲。但不幸的是,图像视图占用的物理空间比图像本身要多。绿色背景仅用于测试目的。透明背景行不通,因为我需要添加圆角,但这些圆角不会可见,因为图像视图的边缘与图像不同步。 - fraggjkee
但我认为我可以尝试通过编程添加相应的纵横比约束...听起来不错 :) 但实际上,我可以在没有AutoLayout的情况下计算和设置所有内容,所以这个问题的想法是要了解是否可以在不编写任何Swift/Objective-C代码的情况下实现。 - fraggjkee
@fraggjkee:好的,但如果你的计划失败了,只需使用我在更新的答案中提供的函数。我已经测试过它可以处理大图和小图、纵向和横向的图片,看起来效果符合预期。 - alexburtnik
是的,纵横比约束条件是解决我的问题的关键,谢谢@alexburtnik。但是,我不是通过编程计算宽度/高度,而是只计算纵横比并更新相应的约束条件。 - fraggjkee
我有一个类似的问题,我正在将一个ImageView和几个其他视图放在ScrollView中。我将ImageView的宽度限制为主视图的宽度,但是发生的情况是,自动布局似乎根据完整大小的图像进行计算,而不是适合大小的图像,因此它会在图像上方和下方创建额外的空间,即使已经有约束条件将图像与上面的视图和下面的视图紧密相连。 - Victor Engel

1

在Interface Builder中尝试勾选“剪裁边界”选项,适用于imageView(剪裁边界图片视图)

同时,您需要定义明确的高度和宽度,不能使用“<=”。


1
这真是救命稻草!我遇到了一个大问题,一个UIImageView有一个纵横比约束,但也有内容模式中的纵横比填充。ImageView只是不断地扩展并覆盖其他内容。甚至不知道如何描述这个问题,但当我无意中阅读到这个0票答案时,它真的拯救了我的一天!谢谢Cristina! - An Chin

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