使用滚动视图缩放图像 Xcode 11 避免 "Ambiguous Content Size" AutoLayout 错误

Use a scrollview to zoom an image in Xcode 11 avoiding the "Ambiguous Content Size" AutoLayout error

我的问题是关于滚动视图的自动布局问题。

我只是想在故事板上添加一个 scrollView,它对 superView 有自己的约束,但其中没有任何子视图,并在应用程序 运行 后在其中添加一个 imageView。但是由于 Storyboard 上的 "ambiguous content size" 错误,autoLayout 在 scrollView 上不起作用,即使我们取消选中选项 "check of ambiguity"。如果我应用将 contentView 添加到 scrollView 的解决方案,并用所有这些额外的约束固定它,我仍然可以捏和缩放 scrollView 内的图像,但失去平移的能力,无论 viewForZoom 是 contentView 还是添加了图像视图。如果 ContentView 是 imageView 我有同样的问题。可以缩放,不能平移。

另外,谁能给我解释一下为什么在这个 Xcode 版本中当 ScrollView 没有内容时会触发这个无意义的 "ambiguous scolding content error"?为什么我们需要将具有两个冗余约束的 contentView 固定到 scrollView 的父视图?

Interface Builder / Storyboard 无法知道您将在 运行 时间添加子视图和约束。

所以,它告诉您您的当前布局的内容大小不明确。

如果滚动视图没有内容,不显示消息会更好吗?也许...但即使它显示设计错误,也不意味着您 必须 修复它。

如果你真的想摆脱 warning/error,几个选项:

1) 在 Storyboard 中添加您的 imageView(具有适当的约束),并在 运行 时间设置 .image 属性。

2) 在 Storyboard 中添加一个子视图(具有适当的约束),并在添加 imageView 之前在 viewdidLoad() 中删除该视图。


编辑

这是一个简单的例子:https://github.com/DonMag/ZoomTest

在 IB / Storyboard 中,我添加了一个 UIScrollView 并且只设置了宽度、高度、centerX 和 centerY 约束,所以 Storyboard 告诉我 Ambiguous Content Size

viewDidLoad 中,我添加了一个 UIImageView,设置适当的约束,设置滚动视图委托和 min/max 缩放比例。


编辑 2

结果使用 256 x 256 图像,并限制滚动视图填充父视图(滚动视图背景为青色)...

加载时 - zoomScale == 1:

加载时 - zoomScale == 1 - 旋转:

zoomScale = 大约 1.5(宽度刚好适合):

zoomScale = 大约 1.5 - 旋转后:

zoomScale == 5 - 平移到左上角:

zoomScale == 5 - 平移到左上角 - 旋转后:

zoomScale == 5 - 平移到右下角:

zoomScale == 5 - 平移到右下角 - 旋转后:

所以,简而言之,解决方案似乎是在故事板上添加 ScrollView 约束,忽略无意义的错误,然后在 viewController 上用 UIImage 初始化 UIImageView 属性,并在 viewDidLoad() 上将 imageView 添加到 scrollView,并使用 NSLayoutConstraint 的 activate() 方法设置 imageView 相对于 scrollView 的 contentLayoutGuide 的约束,将其固定到顶部、底部、左侧和右侧。

实现的例子在这里: https://github.com/HikarusGF/ScrollView-ImageView-Zoom

PS: 我喜欢在storyboard上设置scrollView delegate,所以你不会在代码中看到它。

我终于想出了如何在情节提要上实现它,并让它变得更简单。在几个 XCode 版本之前,它曾经是这样的:

我们仍然可以在 storyboard 上添加一个 ScrollView,它们的典型约束是垂直和水平居中到它的 superView,并且宽度和高度相同,所以 scrollView 可以全屏显示。

到目前为止一切顺利,现在是棘手的部分:在故事板上添加一个 ImageView,作为滚动视图的子视图。在这里,我们需要的约束是将图像视图固定在 SCROLLVIEW 中的四个约束,但绝不是大小约束。如果我们在 ImageView 上使用与 ScrollView 相同的 center/equal-size 约束,那么当涉及到平移,尤其是旋转屏幕时,ScrollView 将显示出完全不稳定和荒谬的行为。

我们仍然会得到荒谬的故事板 warning/error 告诉我们我们的 scrollView 有“不明确的内容大小”,“更新帧”按钮也会有不稳定的行为,但我们可以完全忽略所有这些,并手动调整其中的 ScrollView 和 ImageView 的大小,使其在运行时看起来完全一样。根本不需要额外的冗余约束,尤其是没有触及 ImageView 大小的约束。

我们需要添加到 viewDidLoad() 的唯一代码是委托方法 viewForZooming(),以通知 ScrollView 将哪个子视图用作“可缩放”,在本例中为我们的@IBOutlet UIImageView。必要的最小和最大缩放比例参数也可以在故事板上设置。

func viewForZooming(in scrollView: UIScrollView) -> UIView? { return imageView }

最后,如果我们希望摆脱 scrollView 中的初始边距,因为我们只是显示全屏图像,我们需要设置这个选项,我在 IB 上找不到:

scrollView.contentInsetAdjustmentBehavior = .never

这里是GitHub上的植入项目:https://github.com/HikarusGF/ScrollView-ImageView-Zoom

项目中实现了代码和故事板解决方案。要从一个切换到另一个,只需更改故事板上的初始 viewController。我已将情节提要解决方案设置为默认。