首页 文章

UIScrollView使用自动布局缩放UIImageView

提问于
浏览
10

UIScrollView with UIImageView

考虑具有单个子视图的 UIScrollView . 子视图是 UIImageView ,具有以下大小限制:

  • 其高度必须等于 UIScrollView 的高度 .

  • 其宽度必须是与 UIImageView 的高度成比例缩放的图像宽度 .

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

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

如何使用autolayout实现上述功能,尽可能多地使用Interface builder?

到目前为止我做了什么

基于此answer我配置了我的笔尖:

  • UIScrollView 固定在其超视图的边缘 .

  • UIImageView 固定在 UIScrollView 的边缘 .

  • UIImageView 具有占位符内在大小(以避免Scrollable Content Size Ambiguity错误)

正如预期的那样,结果是 UIImageView 的大小设置为 UIImageUIScrollView 水平和垂直滚动(因为图像大于 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;
}

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

3 回答

  • 2

    在autolayout制度下,理想情况下,UIScrollView contentSize 仅由约束决定,而不是在代码中明确设置 .

    所以在你的情况下:

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

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

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

    这可确保系统仅从约束中派生出 contentSize .

    我已经完成了上述操作,它在iOS 6和7上可靠地运行 UIScrollView 和自定义子视图,所以它也适用于 UIImageView . 特别是如果你没有将子视图固定到滚动视图,iOS 6中的缩放将是紧张的 .

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

  • 11

    只有在代码中实例化视图时才需要 translatesAutoresizingMaskIntoConstraints . 如果您在IB中实例化它,则默认情况下禁用它

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

  • 0

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

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

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

    然后在viewDidLayoutSubviews上我更新了约束:

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

    这似乎可以解决问题 .

相关问题