【问题标题】:UIStackView miscalculating UIImageView heightUIStackView 错误计算 UIImageView 高度
【发布时间】:2016-01-26 23:08:24
【问题描述】:

我有一个 UIStackView 包含在 UICollectionViewCell 中,代表社交网络上的帖子(类似于 Instagram 的单元格)。 UIStackView 包含一个作者标题(自定义UIView),一个用于内容图像的UIImageView,一个用于帖子正文的UILabel,以及一个用于操作的UIToolbar。最终视图看起来像 this

UICollectionViewCell 的高度是通过设置尺寸单元格来设置的,如下所示:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
      NTVFeedBlogCollectionViewCell *cell = [[NTVFeedBlogCollectionViewCell alloc] initWithFrame:CGRectMake(10.0f, 0.0f, collectionView.frame.size.width - 20.0f, 900000.0)];

      // ...
      // Configure the cell
      // ...

      [cell setNeedsLayout];
      [cell layoutIfNeeded];
      CGSize size = [cell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

      return CGSizeMake(CGRectGetWidth(collectionView.frame) - 20.0f, size.height);

}

问题在于 UIImageView 似乎在增加 UICollectionViewCell 的大小,没有增加图像视图的大小。 This is the result 当我将大图像添加到图像视图时。期望的结果是图像保持 1:1 的纵横比,并限制在 UIStackView 的宽度。

正文标签和其余内容之间的间隙大小会根据我使用的图像而变化。这使我相信UIStackView 以某种方式仅考虑单元格的大小 的图像大小,因为从视觉上看,图像视图是正确的大小。正如您在发布的第一张图片中看到的那样,当尚未设置图像视图的图像时,单元格的布局非常完美。

这里是堆栈视图、图像视图和标签的设置代码:

self.stackView = [[UIStackView alloc] initWithFrame:CGRectZero];
self.stackView.translatesAutoresizingMaskIntoConstraints = NO;
self.stackView.axis = UILayoutConstraintAxisVertical;
self.stackView.distribution = UIStackViewDistributionFill;
self.stackView.alignment = UIStackViewAlignmentFill;
self.stackView.spacing = 10.0f;
self.stackView.layoutMargins = UIEdgeInsetsMake(10.0f, 10.0f, 0.0f, 10.0f);
self.stackView.layoutMarginsRelativeArrangement = YES;

[self addSubview:self.stackView];

[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[stackView]-0-|"
                                                             options:0
                                                             metrics:nil
                                                               views:@{@"stackView": self.stackView}]];

[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[stackView]-0-|"
                                                             options:0
                                                             metrics:nil
                                                               views:@{@"stackView": self.stackView}]];

self.imageView = [[UIImageView alloc] initWithFrame:CGRectZero];

[self.imageView setImage:[UIImage imageNamed:@"sample_image.png"]];

self.imageView.translatesAutoresizingMaskIntoConstraints = NO;
self.imageView.contentMode = UIViewContentModeScaleAspectFill;
self.imageView.clipsToBounds = YES;
self.imageView.layer.masksToBounds = YES;
self.imageView.backgroundColor = [UIColor greenColor];

[self.imageView setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];
[self.imageView setContentCompressionResistancePriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisVertical];

[self.stackView addArrangedSubview:self.imageView];

[self.stackView addConstraint:[NSLayoutConstraint constraintWithItem:self.imageView
                                                           attribute:NSLayoutAttributeHeight
                                                           relatedBy:NSLayoutRelationEqual
                                                              toItem:self.stackView
                                                           attribute:NSLayoutAttributeWidth
                                                          multiplier:1.0f
                                                            constant:0.0f]];

self.bodyLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[self.bodyLabel setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];
[self.bodyLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisVertical];
self.bodyLabel.font = [UIFont ntv_lightFontWithSize:17.0f];
self.bodyLabel.textColor = [UIColor whiteColor];
self.bodyLabel.numberOfLines = 0;

self.bodyLabel.text = @"While the stack view allows you to layout its contents without using Auto Layout directly, you still need to use Auto Layout to position the stack view, itself.";
[self.stackView addArrangedSubview:self.bodyLabel];

self.accessoryView = [[NTVAccessoryView alloc] initWithFrame:CGRectZero];
self.accessoryView.viewModel = [NTVAccessoryManagerViewModel_Stubbed new];

[self.stackView addArrangedSubview:self.accessoryView];

有什么想法吗?

【问题讨论】:

标签: ios objective-c uiimageview autolayout uistackview


【解决方案1】:

我们想通了!如文档中所述,UIStackView 使用其arrangedSubviewsintrinsicContentSize 来计算其高度。

UIImageView 将其intrinsicContentSize 报告为图像的整个大小(如您所料)。 UIStackView 忽略了我的高度限制,只是使用图像视图的intrinsicContentSize

为了解决这个问题,我创建了一个UIImageView 子类,它允许调用者设置intrinsicContentSize。这个代码可以在here找到。

然后,在我的UICollectionViewCell 中,一旦布局传递完成,我将设置 UIImageView 子类'intrinsicContentSize

- (void)layoutSubviews {
    [super layoutSubviews];

    // Constrain the image view's content size to match the stackview's width.
    self.imageView.constrainedSize = CGSizeMake(self.stackView.frame.size.width, self.stackView.frame.size.width);

    [super layoutSubviews];

}

【讨论】:

    【解决方案2】:

    如果您不想以编程方式执行此操作,另一种解决方案是垂直使用 2 个 UIStackView。包含 UIImageView 的顶部 UIStackView,将其高度约束设置为占用,例如超级视图高度的 70%,并让底部 UIStackView 紧挨着顶部一个,因此它将占用剩余的 30% 高度。

    这样,无论你的图片有多大,它总是占据高度的 70%。

    【讨论】:

      猜你喜欢
      • 2021-11-04
      • 1970-01-01
      • 2020-04-04
      • 1970-01-01
      • 2020-03-15
      • 2019-07-20
      • 1970-01-01
      • 2014-11-20
      • 1970-01-01
      相关资源
      最近更新 更多