8

I've been struggling with fitting an UIImageView which shows images of variable widths and heights with Aspect Fill. The cell height is not adapting to the new height of the UIImageView and persist it's height.

The hierarchy of the views is this

  • UITableViewCell
    • UITableViewCell.ContentView
      • UIImageView

I tried these scenarios in XCode Auto Layout :

  • set the UIImageView => Height to remove at build time
  • set the Intrinsic Value of the UIImageView to placeholder
  • set the Intrinsic Value for each of the UIImageView, ContentView and UITableViewCell to placeholder

With any of these combinations I get this view:

https://i.stack.imgur.com/Cw7hS.png

The blue lines represent the cell borders (boundaries) and the green ones represent the UIImageView border (boundaries). There are four cells in this example, the 1st and the 3rd ones have no images and the 2nd and the 4th ones have the same image (overflowing over the ones which have none).

Mickey Mouse
  • 1,731
  • 3
  • 24
  • 40
  • Why you not use `.ScaleToFill` instead an calculate what is the width and height of the images you have to set in the cell to expect a better result? – Victor Sigler Mar 15 '15 at 16:24
  • `.ScaleToFill` won't keep the aspect ratio of the images. Consider the case if I have an image with equal height and width (square) and want to fit inside the `UIImageView` it will stretch, I believe. – Mickey Mouse Mar 15 '15 at 16:30
  • Yes you're right but if you calculate the proportions of the width regarding the size of the original image you can set the width of the image more than the cell and the image will keep its aspect. – Victor Sigler Mar 15 '15 at 16:32
  • Let say I did that, how the cell will adjust its height with regard to the height of it's content, specifically the `UIImageView`. consider a scenario where an image is taken by a phone camera in a portrait mode and the height is way bigger than the width of the image. – Mickey Mouse Mar 15 '15 at 16:39

2 Answers2

11

I cobbled together a solution based on two previous answers:

I wanted to keep the AspectRatio of the image regardless of its Height while fixing up the Width according to that of the UIImageView, the container of the image.

The solution comprises of :

  1. Adding a new AspectRatio constraint

    let image = UIImage(ContentFromFile: "path/to/image")
    let aspect = image.size.width / image.size.height
    
    aspectConstraint = NSLayoutConstraint(item: cardMedia, attribute:  NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: cardMedia, attribute: NSLayoutAttribute.Height, multiplier: aspect, constant: 0.0)
    

    when adding this constraint, xCode will complain about the new "redundant" constraint and attempt to break it, rendering it useless, yet displaying the image exactly like I want. This leads me to the second solution

    1. Lowering the priority of the new constrain to '999' seems to stop xcode from breaking it, and it stopped showing warning message about the new constraint

      aspectConstraint?.priority = 999

Not sure why xCode automatically adds UIView-Encapsulated-Layout-Height and UIView-Encapsulated-Layout-Height at build/run time; however, I learned how to respect that and live with it :)

Just leaving the solution here for anyone to check. This is working on iOS 8. I tried with iOS7 but it doesn't work the same as you need to implement tableView:heightForRowAtIndexPath calculating the height of the cell based on all the items contained within it and disable setting up:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44.0
Community
  • 1
  • 1
Mickey Mouse
  • 1,731
  • 3
  • 24
  • 40
  • 1
    It is no need to do this. Too complicated. Just use [imageView setClipsToBounds: YES]. Refer to: https://stackoverflow.com/questions/14609132/crop-uiimage-to-fit-a-frame-image/18285509#18285509 – Jonny Vu Sep 16 '15 at 08:02
  • I don't think you got the question. The question was about letting the UITableViewCell height adapts to the height of the image within it, which is different than fitting the image inside the UIView and clipping its boundaries. – Mickey Mouse Sep 18 '15 at 00:32
  • To be simple, just add a constraint of the height of the image (which is easy to be done in storyboard) and calculate it when setting image. The priority also should be 999. – KChen Mar 14 '16 at 13:28
0

Suppose you have an UIImage with dimensions 768 x 592 of width and height respectively, the height always remains equals, where the device it's rotated for example in the dimensions above (iPad), the width of the image change to 1024 and the height remains equal.

What you can do to maintain the aspect of the image is scale it in the dimensions you want, for example if you know that the images coming always have the same dimensions, we say for example 1280x740 , you can set the UIImage to .ScaleToFill and calculate in the following way:

(widthOfTheImage / heightOfTheImage) * heightWhereYouWanToSet = widthYouHaveToSet

For example :

(1280 / 740) * 592 = 1024

And it's the width I have to set in my UIImage to maintain the proportions of the image when it's change it's width.

I hope you understand where I try to say to you.

Victor Sigler
  • 23,243
  • 14
  • 88
  • 105
  • I think what you are trying to say is how to fit the `UIImage` within the `UIImageView`, right? The issue I have is really not with the `UIImageView` but really with the encompassing cell. I only have a portrait mode for iPhone and the width is always fixed. So the height of the cell is what remains fixed despite the changed height of the `UIImageView` when I fit the image in it. Not sure if we are on the same page here. – Mickey Mouse Mar 15 '15 at 16:59