uitableviewcell - uitableviewautomaticdimension
Diseño automático: obtenga altura UIImageView para calcular la altura de la celda correctamente (5)
Así que creo que el problema subyacente es una especie de problema de huevo y pollo.
Para "adaptar" la imagen a UIImageView
el sistema necesita un tamaño para la vista y, sin embargo, nos gustaría que la altura de la vista se determine después de que el aspecto se ajuste a la imagen con un ancho conocido para la vista.
Una solución consiste en calcular la relación de aspecto de la imagen y establecerla como una restricción en el UIImageView
cuando configuramos la imagen. De esta forma, el sistema de diseño automático tiene suficiente información para ajustar el tamaño de la vista (un ancho y una relación de aspecto).
Así que cambié tu clase de celda personalizada a:
class CustomCell: UITableViewCell {
@IBOutlet weak var imageTitle: UILabel!
@IBOutlet weak var postedImageView: UIImageView!
internal var aspectConstraint : NSLayoutConstraint? {
didSet {
if oldValue != nil {
postedImageView.removeConstraint(oldValue!)
}
if aspectConstraint != nil {
postedImageView.addConstraint(aspectConstraint!)
}
}
}
override func prepareForReuse() {
super.prepareForReuse()
aspectConstraint = nil
}
func setPostedImage(image : UIImage) {
let aspect = image.size.width / image.size.height
aspectConstraint = NSLayoutConstraint(item: postedImageView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: postedImageView, attribute: NSLayoutAttribute.Height, multiplier: aspect, constant: 0.0)
postedImageView.image = image
}
}
Y luego en el delegado haz esto en lugar de configurar la imagen directamente:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as CustomCell
cell.imageTitle.text = titles[indexPath.row]
let image = images[titles[indexPath.row]]!
cell.setPostedImage(image)
return cell
}
Y obtendrás:
¡Espero que esto ayude!
Hasta ahora solo he usado etiquetas de texto dentro de las celdas que deberían auto-dimensionarse. Normalmente pongo restricciones a todos los bordes (vista de contenido o vecinos) y agrego las siguientes líneas a mi viewDidLoad()
:
// 190.0 is the actual height of my custom cell (see next image) in the storyboard containing a label and a randomly sized UIImageView
tableView.estimatedRowHeight = 190.0
tableView.rowHeight = UITableViewAutomaticDimension
Ahora, cuando trato de incluir imágenes, tengo varios problemas. Durante algunas investigaciones, encontré varios enfoques escritos en Objective-C pero, aunque no estoy seguro de cuáles de ellos realmente abordaron mi problema central, todavía estoy luchando con el complejo código Objective-C. Entonces, para resumir: mi objetivo final es obtener una tabla con celdas del tamaño correcto (alturas correctas), cada una con un título y una imagen que se ajuste al ancho de la pantalla. Esas imágenes pueden tener diferentes proporciones de aspecto y diferentes tamaños. Para simplificar algunos de los desafíos, preparé un nuevo proyecto más simple:
- Primero, creé un
UITableViewController
y una claseCustomCell
con dostitle: String
IBOutletstitle: String
ypostedImage: UIImage
(UIImage tamaño aleatorio en el guión gráfico) para configurar las celdas. Definí restricciones a los bordes y entre sí.
- Cuando se construye, se configuran dos celdas que contienen la misma imagen pero se extraen de dos archivos individuales con diferentes tamaños y resoluciones (900 x 171 frente a 450 x 86 de tamaño medio). El modo de vista de UIImage se establece en "Ajuste de aspecto", pero como no pude hacerlo funcionar como quiero hasta ahora, no estoy seguro de que este sea el ajuste correcto. Mientras que yo esperaba que la altura de la celda se calculara en base al UIImage reescalado incluidas las restricciones que había establecido, parece basarse en la altura inicial de los archivos de imagen (por lo tanto, 171 y 86). En realidad, no se adapta a la altura real de la vista UIImage (alrededor de 70 supongo).
En un proyecto mío algo más complejo, quiero que diferentes imágenes se ajusten automáticamente al ancho de la pantalla, sin importar si son verticales o horizontales, y en caso de que su ancho sea inferior al ancho de la pantalla, deberían ampliarse. Al igual que en el proyecto anterior, cada altura de celda debe ajustarse a su contenido individual según lo definido por las restricciones en el guión gráfico. De todos modos, comienza con el problema discutido anteriormente: ¿cómo puedo dejar que esas dos celdas tengan la misma altura, correcta, abrazando su contenido como se define en el guión gráfico?
¡Gracias un millón por cualquier ayuda!
En lugar de tener el método setPostedImage
personalizado, es más conveniente actualizar la restricción de aspecto en updateConstraints
. De esta forma, puedes cambiar la imagen de UIImageView directamente sin método de ayuda adicional:
static NSLayoutConstraint *constraintWithMultiplier(NSLayoutConstraint *constrain, CGFloat multiplier) {
return [NSLayoutConstraint constraintWithItem:constrain.firstItem
attribute:constrain.firstAttribute
relatedBy:constrain.relation
toItem:constrain.secondItem
attribute:constrain.secondAttribute
multiplier:multiplier
constant:constrain.constant];
}
-(void)viewDidLoad
{
UIView *contentView = self.contentView;
_imageView = [[UIImageView alloc] init];
_imageView.translatesAutoresizingMaskIntoConstraints = NO;
_imageView.contentMode = UIViewContentModeScaleAspectFit;
[contentView addSubview:_imageView];
_imageAspectConstraint = [_imageView.heightAnchor constraintEqualToAnchor:_imageView.widthAnchor multiplier:1.0f];
NSArray <NSLayoutConstraint *> *constraints = @[
[_imageView.leadingAnchor constraintEqualToAnchor:contentView.leadingAnchor constant:0],
[_imageView.trailingAnchor constraintEqualToAnchor:contentView.trailingAnchor constant:0],
[_imageView.topAnchor constraintEqualToAnchor:contentView.topAnchor constant:0],
[_imageView.bottomAnchor constraintEqualToAnchor:contentView.bottomAnchor constant:0],
];
[NSLayoutConstraint activateConstraints:constraints];
}
-(void)updateConstraints
{
const CGSize size = _imageView.image.size;
const CGFloat multiplier = size.width / size.height;
_imageAspectConstraint.active = NO;
_imageAspectConstraint = constraintWithMultiplier(_imageAspectConstraint, multiplier);
_imageAspectConstraint.active = YES;
[super updateConstraints];
}
Trabajando en Swift 3 + iOS 8
Usando AutoLayout y objetos UITableViewCell de tamaño variable -
Para la vista de imagen, establezca las restricciones de espacio superior, inferior, inicial y final en 0.
Código que se agregará a viewDidLoad ()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 200
Defina heightForRowAtIndexPath de UITableViewDelegate ()
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let image = UIImage(named: list_images[indexPath.row])
let aspect = (image?.size.width)! / (image?.size.height)!
let cellHeight = (tableView.frame.width / aspect) + <<Height of image title label>>
return cellHeight
}
}
Traduje la solución de Pollard a la versión objc algo así.
También recibí advertencias como "Incapaz de satisfacer restricciones simultáneamente". Mi solución establece la prioridad de la restricción de espacio vertical como 999 en lugar de 1000.
@interface PostImageViewCell()
@property (nonatomic, strong) NSLayoutConstraint *aspectContraint;
@end
@implementation PostImageViewCell
- (void) setAspectContraint:(NSLayoutConstraint *)aspectContraint {
if (_aspectContraint != nil) {
[self.postImage removeConstraint:_aspectContraint];
}
if (aspectContraint != nil) {
[self.postImage addConstraint:aspectContraint];
}
}
- (void) prepareForReuse {
[super prepareForReuse];
self.aspectContraint = nil;
}
- (void)setPicture:(UIImage *)image {
CGFloat aspect = image.size.width / image.size.height;
self.aspectContraint = [NSLayoutConstraint constraintWithItem:self.postImage
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.postImage
attribute:NSLayoutAttributeHeight
multiplier:aspect
constant:0.0];
[self.postImage setImage:image];
}
@end
Swift 4
Calcule la altura de la imagen usando la extension
UIImage
.
Puede usar la siguiente extension
de UIImage
para obtener la altura de acuerdo con AspectRatio de la imagen.
extension UIImage {
var cropRatio: CGFloat {
let widthRatio = CGFloat(self.size.width / self.size.height)
return widthRatio
}
}
Por lo tanto, dentro de su override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
método override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
.
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let currentImage = dataSource[indexPath.row].image
let imageCrop = currentImage.cropRatio
var _height = tableView.frame.width / imageCrop
return _height
}