Dynamic UIImageView Size Within UITableView

前端 未结 6 1347
伪装坚强ぢ
伪装坚强ぢ 2020-12-04 13:46

I want to implement a TableView with a Custom TableViewCell showing an image.

To make this simple, I simply put a UIImageView inside a tableviewcell using autolayout

相关标签:
6条回答
  • 2020-12-04 14:08

    Remove the height constraint from your imageView. Choose the contentMode of image view that starts with "aspect" eg: aspect fill or aspect fit (as it fits according to your requirements).

    NOTE: You also need to set the height of the row so that the imageView fits in it. Use

    heightForRowAtIndexPath
    

    to set custom row height.

    0 讨论(0)
  • 2020-12-04 14:09
    1. make sure you have set top-bottom constraints in storyboard.
    2. save the thumbnail/image as data to local storage (I'm using core data)
    3. using the thumb image, calculate the aspect of the image
    4. customise the row height as you want in heightForRowAt method.
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            let entity = self.fetchedResultController.object(at: indexPath as IndexPath) as! Message
            var newh:CGFloat = 100.00
    
            if let fileThumbnails =  entity.file_thumbnails as? NSArray{
                if fileThumbnails.count != 0{
                    fileThumbnails.map { (thumbNail) in
                        newh = self.getImageHeight(image:UIImage(data: thumbNail as! Data)! , h: UIImage(data: thumbNail as! Data)!.size.height , w: UIImage(data: thumbNail as! Data)!.size.width)
                    }
    
                }
    
            }
    
            if entity.fileStatus == "DeletedMedia" {
                newh = 100
            }
            if entity.fileStatus == nil{
                newh = 0.0
            }
            print ("newH " , newh)
            return newh
        }
        func getImageHeight(image : UIImage, h : CGFloat, w : CGFloat) -> CGFloat {
            let aspect = image.size.width / image.size.height
            var newH = (messagesTV.frame.size.width) / aspect
            // customise as you want in newH
            if(newH > 500){
                newH = 500
               //maximum height 500
            }
            if(newH < 100){
                newH = 100
                //minimum height = 100
            }
            return newH
        }
    

    if the thumb image is deleted in local storage then a placeholder image will be shown. you can customise the newHvariable to get the desired output

    if you want to change the params like a fixed width then change it in the newH variable in getImageHeight() method. eg: var newH = (messagesTV.frame.size.width * 0.6) / aspect I will get height with aspect based on the width I mentioned here in this example, my fixed width is 60% width of the screen. hope this helps!

    0 讨论(0)
  • 2020-12-04 14:13

    While loading images into the tableView each image can be with diffrent aspect ratio. With using of SDWebImage we can get the image from url as -

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

    In UITableViewCell set the constraint for imageView as top, bottom, leading, trailing, fixed height constraint with 999 priority And change height-constraint-constant according to 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!)
    
            })
    

    Calculate cell frame & find the respective height based on that.

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

    Example on Github

    0 讨论(0)
  • 2020-12-04 14:18

    Swift 4.0

    You can use simple code to manage the height of row according to the height of imageView in tableView cell.

       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 讨论(0)
  • 2020-12-04 14:21

    If you want the UIImageView to tell the UITableView how tall it needs to be, then you need to configure the table view to enable automatic row calculation. You do this by setting estimatedRowHeight to a fixed positive value and setting rowHeight to UIViewAutomaticDimension. That's part one.

    Now you need to configure the UIImageView to request a height based on the width which the table view requires and on the aspect ratio of the image. This will be part two.

    First, set the contentMode to .AspectFit. This will cause the view to resize the appearance of the image based on whatever dimensions it takes. However, this still doesn't cause it to request the needed height with auto layout. Instead, it will request the height of the intrinsicContentSize, which may be quite different from the resized image. So, second, add a constraint to the UIImageView that is of the form width = height * multiplier, where the multiplier is based on the aspect ratio of the image itself.

    Now the table view will require the correct width, the contentMode mechanism will ensure the image is resized correctly without distortion, and the aspect ration constraint will ensure that the image view requires the correct height via auto layout.

    This works. The downside of it is that you will need to update the aspect ratio constraint every time you assign a new image to the image view, which could be quite often if the image view is in a cell that's getting re-used.

    An alternative approach is to add only a height constraint and update it in the layoutSubviews of a view containing the image view. This has better performance but worse code modularity.

    0 讨论(0)
  • 2020-12-04 14:27

    In the storyboard add trailing, leading, bottom and top constraints to your UIImageView. After you load your image all you need to do is add an aspect constraint to your UIImageView. Your images cell would look something like this:

    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
        }
    }
    

    You can check working example here DynamicTableWithImages

    0 讨论(0)
提交回复
热议问题