UIStackView calculates the height of a UIImageView

I have a UIStackView contained inside a UICollectionViewCell to represent a post on a social network (similar style for Instagram mailboxes). UIStackView contains the authorโ€™s title (custom UIView ), UIImageView for the image content, UILabel for the message body and UIToolbar for actions. The final look looks like this .

The height of the UICollectionViewCell is set by adjusting the cell with dimensions, for example:

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

The problem is that the UIImageView seems to increase the size of the UICollectionViewCell without increasing the size of the image. This is the result when I add a large image to the image view. The desired result is that the image remains proportional to 1: 1, limited by the width of the UIStackView.

The size of the gap between the body mark and the rest of the content varies depending on which image I am using. This makes me think that UIStackView somehow takes into account the size of the image to select the cell size, because visually the image is the correct size. As you saw in the first image posted, the cell is perfectly debugged when the image image is not installed.

Here is the installation code for presenting the stack, viewing the image and labels:

 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]; 

Any ideas?

+6
source share
2 answers

We got it! As stated in the docs, UIStackView uses the intrinsicContentSize its arrangedSubviews to calculate its height.

UIImageView reports its intrinsicContentSize as the entire size of the image (as you would expect). UIStackView ignored my height limit and just used intrinsicContentSize for the image.

To fix this, I created a subclass of UIImageView that allows the caller to set intrinsicContentSize . This code can be found here .

Then in my UICollectionViewCell I set the subclass of UIImageView ' intrinsicContentSize after the layout is complete:

 - (void)layoutSubviews { [super layoutSubviews]; // Constrain the image view content size to match the stackview width. self.imageView.constrainedSize = CGSizeMake(self.stackView.frame.size.width, self.stackView.frame.size.width); [super layoutSubviews]; 

}

+7
source

Another solution, if you do not want to do this programmatically, is to use 2 UIStackViews vertically. The top UIStackView, which contains the UIImageView, sets a height limit, for example, 70% of the height of the labels, and let the bottom UIStackView be near the top, so it will occupy the remaining 30% of the height.

Thus, no matter how large your image is, it will always occupy 70% of the height.

0
source

All Articles