MyLocations Exercise: Dynamic UITableViewCell Height without AutoLayout? (Partial Solution)

Problem

I currently return a global var holding the correct heightForRowAtIndexPath, however, the image no longer pins itself to the top left corner. The UIImageView is pinned to the top left using the size inspector.

####Question: How to solve this without using Auto-layout and constraints?

My Solution

Global Variable: var dynamicHeight: CGFloat = 0.0

    var image: UIImage? {
        didSet {
            if let image = image {
                imageView.image = image
                imageView.hidden = false
                addPhotoLabel.hidden = true
                imageView.frame = CGRect(x: 10, y: 10, width: 260, height: 260)
                
                let aspectRatio = image.size.width / image.size.height
                dynamicHeight = (280 / aspectRatio)
            }
        }
    }

My solution is quite similar to yours. There is one difference though how I calculate the height of the table view cell:

dynamicHeight = (CGFloat(260) / aspectRatio) + 20

I also had a problem with the image being pinned to the top border of the cell. In the size inspector / autoresizing make sure that the image view is pinned to the top and left borders.

Hope this helps.

I did this a little differently. I adjusted the table height (dynamically?) in the function tableView( heightForRowAt

                let aspectRatio = (image?.size.width)! / (image?.size.height)!
                let rowHeight = (260.0 / aspectRatio) + 20.0
                
                return rowHeight

AND the image frame height in the function show(image

let aspectRatio = image.size.width / image.size.height
let imageHeight = 260.0 / aspectRatio

imageView.frame = CGRect(x: 10, y: 10, width: 260, height: imageHeight)

Sometimes not quite perfect on the simulator (with the provided images). I wonder if choosing a non edited image makes a difference. Where was dynamicHeight declared?


I tried a change in imagePickerController(

        if let theImage = info[UIImagePickerControllerEditedImage] as? UIImage
        {
            image = theImage
        }
        else if let theImage = info[UIImagePickerControllerOriginalImage] as? UIImage
        {
            image = theImage
        }
        
        if let theImage = image
        {
            show(image: theImage)
        }

but it didn’t seem to help. I appears that the first adjustment doesn’t always work. Maybe using the approach using didSet is better although I don’t see where dynamicHeight is defined?


It looks like adding the pinning to top/left for the image view fixes the problem, as mentioned by linc. The Add Photo text label was ‘already’ pinned top/left.

Thanks guys for your solutions!
Looking at them I could cope with this task!

So here it is.

First add a new instance variable:

var dynamicHeight = CGFloat()

Next change the image variable implementation to this:

var image: UIImage? {
  didSet {
    if let theImage = image {
      let aspectRatio = theImage.size.width / theImage.size.height
      dynamicHeight = (CGFloat(260) / aspectRatio)
    
      imageView.image = theImage
      imageView.isHidden = false
      imageView.frame = CGRect(x: 10, y: 10, width: 260, height: dynamicHeight)
      addPhotoLabel.isHidden = true
    }
  }
}

Then in tableView(_ tableView:heightForRowAt indexPath:) change the if statement to:

} else if indexPath.section == 1 {
  if imageView.isHidden {
    return 44
  } else {
    return dynamicHeight + 20
  }
}

We can’t control the position and size of the image view through the storyboard, and anything you change in the size inspector regarding to the autoresize won’t take effect, as we set the parameters of the view through the code.

And what should we do in the code is to:

  • calculate the dynamicHeight;
  • set it as the actual height parameter of our imageView’s frame property;
  • set the heightForRow of the 1st section 20 points bigger than the dynamicHeight.



UPD1: And after refactoring the code we have:

override func tableView(_ tableView: UITableView,
           heightForRowAt indexPath: IndexPath) -> CGFloat {
  ...
  case (1, _):
    return imageView.isHidden ? 44 : (dynamicHeight + 20)
  ...
}

Tried this out even using panorama images — works perfectly! :wink:




UPD2: Later in the chapter we’ll actually need the show(image:) method to show the images in the “Edit Locations” screen, so change the function to:

func show(image: UIImage) {
  let aspectRatio = image.size.width / image.size.height
  dynamicHeight = (CGFloat(260) / aspectRatio)

  imageView.image = image
  imageView.isHidden = false
  imageView.frame = CGRect(x: 10, y: 10, width: 260, height: dynamicHeight)
  addPhotoLabel.isHidden = true
}

and the image variable to:

var image: UIImage? {
  didSet {
    if let theImage = image {
      show(image: theImage)
    }
  }
}