Auto-Layout: Obtener UIImageView height para calcular correctamente la altura de la celda
Hasta ahora solo he estado usando etiquetas de texto dentro de las celdas que deben 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, al tratar de incluir con imágenes, me enfrento a varios problemas. Durante algunas investigaciones encontré varios enfoques escritos en Objective-C, pero mientras que no estoy seguro de cuál de ellos realmente abordó mi problema central, todavía estoy luchando con el complejo código Objective-C. Tan para reanudar: Mi objetivo final es obtener una tabla con celdas de 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 relaciones de aspecto y diferentes tamaños. Para simplificar algunos de los desafíos, preparé un nuevo proyecto más simple:
- Primero, creé una clase
UITableViewController
y unaCustomCell
con dos IBOutletstitle: String
ypostedImage: UIImage
(UIImage de tamaño aleatorio en el guion gráfico) para configurar las celdas. I defined constraints to the bordes y uno a otro.
- Cuando se construyen, se configuran dos celdas que contienen la misma imagen, pero se obtienen de dos archivos individuales con diferentes tamaños y resoluciones (900 x 171 vs.450 x 86 de tamaño medio). El modo de vista UIImage está configurado en" Ajuste de aspecto", pero como no pude ejecutarlo de la manera que quiero hasta ahora, no estoy seguro de que este sea el ajuste correcto. Mientras que yo había esperado que la altura de la celda se calculara en función de la imagen UIImage restricciones que había establecido, parece estar basado en la altura inicial de los archivos de imagen (por lo 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 menor que el ancho de la pantalla, deben ampliarse. Como en el proyecto de arriba la altura de la celda debe ajustarse a su contenido individual según lo definido por las restricciones en el guion gráfico. De todos modos, comienza con el problema discutido anteriormente: ¿Cómo puedo permitir que esas dos celdas tengan la misma altura correcta, abrazando su contenido como se define en el guion gráfico?
Un millón de gracias por cualquier ayuda!
5 answers
Así que creo que el problema subyacente es una especie de problema de pollo y huevo.
Para 'ajustar el aspecto' de la imagen al UIImageView
el sistema necesita un tamaño para la vista, y sin embargo nos gustaría que la altura de la vista se determinara después de ajustar el aspecto de la imagen dada una anchura conocida para la vista.
Una solución es calcular la relación de aspecto de la imagen nosotros mismos y establecerla como una restricción en el UIImageView
cuando establecemos la imagen. De esa manera el sistema de diseño automático tiene suficiente información para dimensionar 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 hacer 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!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-26 10:00:03
Traduje la solución de Pollard a la versión objc algo así.
También recibí advertencias como "Incapaz de satisfacer simultáneamente las restricciones". Mi solución es establecer la prioridad de 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-16 20:28:19
Trabajando en Swift 3 + iOS 8
Usando objetos de diseño automático y tamaño variable UITableViewCell -
Para imageview, establezca las restricciones de espacio superior, inferior, inicial y final en 0.
Código a añadir a viewDidLoad ()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 200
Define la altura de UITableViewDelegate pararowatindexpath ()
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
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-29 20:15:29
En lugar de tener un método personalizado setPostedImage
, es más conveniente actualizar la restricción de aspecto en updateConstraints
. De esta manera, puede cambiar la imagen de UIImageView directamente sin el método auxiliar 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];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-06 05:33:43
Swift 4
Calcular la altura de la imagen usando UIImage
extension
.
Puede usar el siguiente extension
de UIImage
para obtener la Altura de acuerdo con la 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 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
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-01 13:42:45