11

UIScrollView 与 UIImageView

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

  • 它的高度必须等于 的高度UIScrollView
  • 它的宽度必须是与UIImageView.

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

图像可能在viewDidLoad(如果缓存)期间或异步设置。

您如何使用自动布局实现上述功能,尽可能多地使用界面生成器?

到目前为止我所做的

基于这个答案,我这样配置我的笔尖:

  • UIScrollView固定在其父视图的边缘。
  • UIImageView固定到 的边缘UIScrollView
  • 具有UIImageView占位符固有大小(以避免Scrollable Content Size Ambiguity错误)

正如预期的那样,结果是 的UIImageView大小与 的大小相同UIImage,并且UIScrollView水平和垂直滚动(因为图像大于UIScrollView)。

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

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

没有自动布局

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

- (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;
}

我正在努力转向自动布局,但这并不容易。

4

3 回答 3

11

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

所以在你的情况下:

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

  • 为您的子视图创建高度和宽度约束。否则,固有尺寸UIImageView决定了它的高度和宽度。在设计时,这个尺寸只是一个让 Interface Builder 满意的占位符。在运行时,它将设置为实际图像大小,但这不是您想要的。

  • 在 期间viewDidLayoutSubviews,将约束更新为实际内容大小。constant您可以通过更改高度和宽度约束的属性直接执行此操作,也可以调用setNeedsUpdateConstraints和覆盖updateConstraints来执行相同操作。

这确保了系统可以contentSize仅从约束中导出。

我已经完成了上述操作,它可以在带有自定义子视图的 iOS 6 和 7 上可靠地UIScrollView工作,所以它也应该可以工作UIImageView。特别是如果您不将子视图固定到滚动视图,则在 iOS 6 中缩放会很紧张。

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

于 2013-10-29T01:20:03.613 回答
2

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

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

于 2013-10-28T12:09:46.250 回答
1

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

我在 UIImageView 上设置了另一个约束,其宽度与 UIScrollView 的宽度相匹配,因为它在界面构建器中,然后向 UIViewController 添加了一个出口:

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

然后在 viewDidLayoutSubviews 我更新了约束:

- (void) viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    self.imageViewWidthConstraint.constant = CGRectGetWidth(self.scrollView.frame);
}

这似乎奏效了。

于 2015-07-03T12:05:13.390 回答