ios - example - uistackview swift 3
UIStackView cálculo erróneo de UIImageView height (2)
¡Lo descubrimos! Como se indica en los documentos, UIStackView
está utilizando el intrinsicContentSize
de sus UIStackView
para calcular su altura.
UIImageView
informa de su intrinsicContentSize
como el tamaño completo de la imagen (como era de esperar). UIStackView
estaba ignorando mi restricción de altura y solo usaba el tamaño de UIStackView
intrinsicContentSize
de la vista de imagen.
Para solucionarlo, he creado una subclase UIImageView
que permite que un interlocutor establezca el intrinsicContentSize
. Este código se puede encontrar aquí .
Luego, en mi UICollectionViewCell
estoy configurando la subclase UIImageView '' intrinsicContentSize
una vez que el pase de diseño se haya completado:
- (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];
}
Tengo una UIStackView
contenida dentro de UICollectionViewCell
para representar una publicación en una red social (estilo similar a las celdas de Instagram). El UIStackView
contiene un encabezado de autor ( UIView
personalizado), un UIImageView
para la imagen de contenido, un UILabel
para el cuerpo del mensaje y un UIToolbar
para las acciones. La vista final se ve así.
La altura de UICollectionViewCell se establece configurando una celda de tamaño, de esta manera:
- (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);
}
El problema es que UIImageView parece aumentar el tamaño de UICollectionViewCell, sin aumentar el tamaño de la vista de imagen. Este es el resultado cuando agrego una imagen grande a la vista de la imagen. El resultado deseado es que la imagen permanezca en una relación de aspecto de 1: 1, limitada al ancho de UIStackView.
El tamaño del espacio entre la etiqueta del cuerpo y el resto del contenido cambia según la imagen que uso. Esto me lleva a creer que UIStackView
alguna manera está teniendo en cuenta el tamaño de la imagen para el tamaño de la celda solamente, ya que visualmente la vista de la imagen tiene su tamaño correcto. Como viste en la primera imagen publicada, la celda se establece perfectamente cuando la imagen de la vista de imagen no se ha configurado.
Aquí está el código de configuración para la vista de la pila, la vista de la imagen y las etiquetas:
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];
¿Algunas ideas?
La otra solución, si no quieres hacerlo programáticamente, es usar 2 UIStackViews verticalmente. El UIStackView superior que contiene UIImageView, establece su restricción de altura para asumir, digamos el 70% de la altura de la supervista, y permite que el UIStackView inferior se coloque justo al lado del superior, por lo que ocupará el 30% de altura restante.
De esta manera, no importa cuán grande sea tu imagen, siempre tomará el 70% de la altura.