使用自动布局缩放UIImageView的UIScrollView

UIImageView的UIScrollView

考虑一个具有单个子视图的UIScrollView 。 子视图是具有以下大小约束的UIImageView

  • 它的高度必须等于UIScrollView的高度。
  • 它的宽度必须是图像的宽度,与UIImageView的高度成比例。

预计UIImageView的宽度将比UIScrollView的宽度大,因此需要滚动。

该图像可能会在viewDidLoad (如果caching)或asynchronous时设置。

你如何使用自动布局实现上述function,尽可能多地使用Interface Builder?

到目前为止我所做的

基于这个答案,我configuration我的笔尖是这样的:

  • UIScrollView固定在其超视图的边缘。
  • UIImageView固定在UIScrollView的边缘。
  • UIImageView具有占位符的固有大小(以避免可滚动内容大小歧义错误)

正如所料,结果是UIImageView的大小为UIImage的大小,并且UIScrollView水平和垂直滚动(因为图像大于UIScrollView )。

然后我尝试了各种不起作用的东西:

  • 在手动加载图像后设置UIImageView的框架。
  • 在UIImageView的宽度上添加一个约束,并在载入图像后修改它的值。 这使图像更大(?!)。
  • 图像加载后设置zoomScale 。 没有明显的效果。

没有自动布局

以下代码完全按照我的要求,尽pipe没有自动布局或界面生成器。

 - (void)viewDidLoad { { UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [self.view addSubview:scrollView]; self.scrollView = scrollView; } { UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height)]; imageView.contentMode = UIViewContentModeScaleAspectFit; imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [self.scrollView addSubview:imageView]; self.scrollView.contentSize = imageView.frame.size; self.imageView = imageView; } } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; [self layoutStripImageView]; } - (void)layoutStripImageView { // Also called when the image finishes loading UIImage *image = self.imageView.image; if (! image) return; const CGSize imageSize = image.size; const CGFloat vh = self.scrollView.frame.size.height; const CGFloat scale = vh / imageSize.height; const CGFloat vw = imageSize.width * scale; CGSize imageViewSize = CGSizeMake(vw, vh); self.imageView.frame = CGRectMake(0, 0, imageViewSize.width, imageViewSize.height); self.scrollView.contentSize = imageViewSize; } 

我努力想要自动布局,但这并不容易。

在自动布局机制下,理想情况下,UIScrollView contentSize完全由约束决定,而不是在代码中明确设置。

所以在你的情况下:

  • 创build约束来将子视图固定到UIScrollView 约束必须确保子视图和滚动视图之间的边距为0.我看到你已经试过这个。

  • 为您的子视图创build一个高度和宽度约束。 否则, UIImageView的内在大小决定了其高度和宽度。 在devise时,这个大小只是一个占位符来保持Interface Builder的快乐。 在运行时,它将被设置为实际的图像大小,但这不是你想要的。

  • viewDidLayoutSubviews期间,将约束更新为实际的内容大小。 你可以直接通过改变高度和宽度约束的constant属性,或者调用setNeedsUpdateConstraints和覆盖updateConstraints来做同样的事情。

这确保系统可以仅从约束派生contentSize

我已经完成了上述工作,它可以在iOS 6和7上使用UIScrollView和自定义子视图可靠地工作,因此它也可以用于UIImageView 。 特别是如果你不把子视图固定在滚动视图上,在iOS 6中缩放将会不安。

您也可以尝试创build直接引用滚动视图的高度和宽度的倍数的高度和宽度约束,但是我没有尝试使用其他方法。

只有当您在代码中实例化视图时才需要translatesAutoresizingMaskIntoConstraints 。 如果你在IB中实例化它,它默认是禁用的

在我看来,UIImageView应该填充ScrollView。 稍后我会尝试将scrollview的缩放设置为适合您的值,以便图像只能朝一个方向平移

在我的情况下,这是一个全宽的UIImageView有一个定义的高度约束,导致问题。

我在UIImageView上设置了与UIScrollView的宽度相匹配的宽度,就像在界面生成器中一样,然后在UIViewController中添加了一个插口:

 @property (weak, nonatomic) IBOutlet NSLayoutConstraint *imageViewWidthConstraint; 

然后在viewDidLayoutSubviews我更新了约束:

 - (void) viewDidLayoutSubviews { [super viewDidLayoutSubviews]; self.imageViewWidthConstraint.constant = CGRectGetWidth(self.scrollView.frame); } 

这似乎是诀窍。