web-dev-qa-db-fra.com

Taille UIImageView dynamique dans UITableView

Je veux implémenter une TableView avec une TableViewCell personnalisée montrant une image.

Pour simplifier les choses, j’ai simplement placé UIImageView dans une tableviewcell en utilisant autolayout (illustré ci-dessous) .  enter image description here

Ce que je veux, c’est d’afficher l’image à l’intérieur d’un UIImageView, mais ces dimensions peuvent être quelconques et sont incohérentes (portrait, paysage, carré) ...

Par conséquent, je cherche à afficher une image avec une largeur fixe (la largeur du périphérique) et une hauteur dynamique qui respecte le rapport des images. Je veux quelque chose comme ça:
 enter image description here

Je n'ai malheureusement pas réussi à atteindre ce résultat.

Voici comment je l'ai implémentée - (J'utilise Haneke pour charger l'image à partir d'une URL - image stockée dans Amazon S3):

class TestCellVC: UITableViewCell {

    @IBOutlet weak var selfieImageView: UIImageView!
    @IBOutlet weak var heightConstraint: NSLayoutConstraint!

    func loadItem(#selfie: Selfie) {        
        let selfieImageURL:NSURL = NSURL(string: selfie.show_selfie_pic())!

        self.selfieImageView.hnk_setImageFromURL(selfieImageURL, placeholder: nil, format: HNKFormat<UIImage>(name: "original"), failure: {error -> Void in println(error)
            }, success: { (image) -> Void in
                // Screen Width
                var screen_width = UIScreen.mainScreen().bounds.width

                // Ratio Width / Height
                var ratio =  image.size.height / image.size.width

                // Calculated Height for the picture
                let newHeight = screen_width * ratio

                // METHOD 1
                self.heightConstraint.constant = newHeight

                // METHOD 2
                //self.selfieImageView.bounds = CGRectMake(0,0,screen_width,newHeight)

                self.selfieImageView.image = image
            }
        )
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Register the xib for the Custom TableViewCell
        var nib = UINib(nibName: "TestCell", bundle: nil)
        self.tableView.registerNib(nib, forCellReuseIdentifier: "TestCell")

        // Set the height of a cell dynamically
        self.tableView.rowHeight = UITableViewAutomaticDimension
        self.tableView.estimatedRowHeight = 500.0

        // Remove separator line from UITableView
        self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None

        loadData()
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCellWithIdentifier("TestCell") as TestCellVC


        cell.loadItem(selfie: self.selfies_array[indexPath.row])
        // Remove the inset for cell separator
        cell.layoutMargins = UIEdgeInsetsZero
        cell.separatorInset = UIEdgeInsetsZero

        // Update Cell Constraints
        cell.setNeedsUpdateConstraints()
        cell.updateConstraintsIfNeeded()
        cell.sizeToFit()

        return cell
    }
}

Mon calcul de la hauteur dynamique est correct (je l'ai imprimé). J'ai essayé les deux méthodes (décrire dans le code) mais aucune d'entre elles n'a fonctionné:

  1. Définir la contrainte de hauteur automatique de UIImageView
  2. Modifier le cadre de UIImageView

Voir les résultats des méthodes 1 et 2 ici: imageImage 2

17
fabdarice

Dans le storyboard, ajoutez des contraintes de fin, de début, de haut et de bas à votre UIImageView. Après avoir chargé votre image, il vous suffit d'ajouter une contrainte d'aspect à votre UIImageView. Votre cellule d'images ressemblerait à quelque chose comme ceci: 

class ImageTableViewCell: UITableViewCell {

    @IBOutlet weak var customImageView: UIImageView!

    internal var aspectConstraint : NSLayoutConstraint? {
        didSet {
            if oldValue != nil {
                customImageView.removeConstraint(oldValue!)
            }
            if aspectConstraint != nil {
                customImageView.addConstraint(aspectConstraint!)
            }
        }
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        aspectConstraint = nil
    }

    func setCustomImage(image : UIImage) {

        let aspect = image.size.width / image.size.height

        let constraint = NSLayoutConstraint(item: customImageView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: customImageView, attribute: NSLayoutAttribute.height, multiplier: aspect, constant: 0.0)
        constraint.priority = 999

        aspectConstraint = constraint

        customImageView.image = image
    }
}

Vous pouvez consulter l'exemple de travail ici DynamicTableWithImages

12
sash

 enter image description here

Lors du chargement des images dans la table, chaque image peut avoir un rapport de format différent . Avec l’utilisation de SDWebImage nous pouvons obtenir l’image à partir de l’URL sous la forme -

 testImageView.sd_setImage(with: url, placeholderImage: nil, options: [], completed: { (downloadedImage, error, cache, url) in
            print(downloadedImage?.size.width)//prints width of image
            print(downloadedImage?.size.height)//prints height of image
        })

Dans UITableViewCell, définissez la contrainte pour imageView sur top, bottom, leading, trailing, fixed height constraint avec une priorité de 999 Et changez height-constraint-constant en fonction de l'image.

 var cellFrame = cell.frame.size
 cellFrame.height =  cellFrame.height - 15
 cellFrame.width =  cellFrame.width - 15
 cell.feedImageView.sd_setImage(with: url, placeholderImage: nil, options: [], completed: { (theImage, error, cache, url) in
            cell.feedImageHeightConstraint.constant = self.getAspectRatioAccordingToiPhones(cellImageFrame: cellFrame,downloadedImage: theImage!)

        })

Calculez le cadre de la cellule et recherchez la hauteur respective en fonction de cela.

  func getAspectRatioAccordingToiPhones(cellImageFrame:CGSize,downloadedImage: UIImage)->CGFloat {
        let widthOffset = downloadedImage.size.width - cellImageFrame.width
        let widthOffsetPercentage = (widthOffset*100)/downloadedImage.size.width
        let heightOffset = (widthOffsetPercentage * downloadedImage.size.height)/100
        let effectiveHeight = downloadedImage.size.height - heightOffset
        return(effectiveHeight)
    }

Exemple sur Github

9
Jack

Si vous voulez que UIImageView indique à UITableView quelle doit être sa hauteur, vous devez configurer la vue tabulaire pour permettre le calcul automatique des lignes. Pour ce faire, vous devez définir ratedRowHeight sur une valeur positive fixe et définir rowHeight sur UIViewAutomaticDimension. C'est la première partie. 

Vous devez maintenant configurer UIImageView pour demander une hauteur basée sur la largeur requise par la vue tableau et sur le format de l'image. Ce sera la deuxième partie. 

Tout d’abord, définissez le contentMode sur .AspectFit. Ainsi, la vue redimensionnera l'apparence de l'image en fonction de ses dimensions. Cependant, cela ne l'oblige toujours pas à demander la hauteur nécessaire avec la mise en page automatique. Au lieu de cela, il demandera la hauteur intrinsèqueContentSize, qui peut être assez différente de l'image redimensionnée. Ensuite, ajoutez une contrainte à UIImageView de la forme width = height * multiplier, où le multiplicateur est basé sur le rapport de format de l'image elle-même.

Désormais, la vue de tableau nécessitera la largeur correcte, le mécanisme contentMode garantira le redimensionnement correct de l'image sans distorsion et la contrainte de rapport d'aspect garantira que la vue de l'image requiert la hauteur correcte via la mise en page automatique. 

Cela marche. L'inconvénient est que vous devrez mettre à jour la contrainte de rapport d'aspect chaque fois que vous affectez une nouvelle image à la vue d'image, ce qui peut se produire assez souvent si la vue d'image se trouve dans une cellule en cours de réutilisation.

Une approche alternative consiste à ajouter uniquement une contrainte de hauteur et à la mettre à jour dans les sous-vues layoutSublies d'une vue contenant la vue d'image. Cela a de meilleures performances mais une moins bonne modularité du code.

3
algal

Swift 4.0

Vous pouvez utiliser un code simple pour gérer la hauteur de ligne en fonction de la hauteur de imageView dans la cellule tableView.

   func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if let height = self.rowHeights[indexPath.row]{
            return height
        }else{
            return defaultHeight
        }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return imageArray.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let identifier = "editImageCell"
        let customCell : EdiPostImageCell = (self.imagesTableView.dequeueReusableCell(withIdentifier: identifier)) as! EdiPostImageCell
        let aspectRatio = (imageArray[indexPath.row]).size.height/(imageArray[indexPath.row]).size.width
        customCell.editlImageView.image = imageArray[indexPath.row]
        let imageHeight = self.view.frame.width*aspectRatio
        self.imagesTableView.beginUpdates()
        self.rowHeights[indexPath.row] = imageHeight
        tableView.endUpdates()
    }
0

Supprimez la contrainte de hauteur de votre imageView. Choisissez le contentMode de la vue d'image qui commence par "aspect", par exemple: aspect ou remplissage (comme il convient en fonction de vos besoins).

NOTE: Vous devez également définir la hauteur de la ligne de sorte que l'imageView puisse s'y adapter. Utilisation

heightForRowAtIndexPath

définir la hauteur de ligne personnalisée.

0
Rohit Kumar