【问题标题】:UIScrollView with scaled UIImageView using autolayoutUIScrollView 与使用自动布局的缩放 UIImageView
【发布时间】:2013-11-07 04:03:27
【问题描述】:

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

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

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

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

您如何使用自动布局实现上述功能,并尽可能多地使用 Interface builder?

到目前为止我做了什么

基于answer,我这样配置我的笔尖:

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

我非常努力地转向自动布局,但这并不容易。

【问题讨论】:

    标签: ios uiscrollview uiimageview interface-builder autolayout


    【解决方案1】:

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

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

    【讨论】:

    • 我试过了。 zoomScale 似乎对 UIScrollView 没有影响。
    • 编辑问题以删除translatesAutoresizingMaskIntoConstraints
    【解决方案2】:

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

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

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

    然后在 viewDidLayoutSubviews 我更新了约束:

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

    这似乎可以解决问题。

    【讨论】:

      【解决方案3】:

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

      所以在你的情况下:

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

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

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

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

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

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

      【讨论】:

      • 非常感谢!设置高度和宽度约束对我有用。
      猜你喜欢
      • 2013-01-06
      • 2014-11-27
      • 2012-12-11
      • 1970-01-01
      • 2013-01-04
      • 1970-01-01
      • 1970-01-01
      • 2014-01-15
      • 2012-02-12
      相关资源
      最近更新 更多