Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xcode Imageview Aspect Fit Remove Extra Space

I have an imageview inside a UITableViewCell.

Imageview with Aspect Fit creates a lot of extra space in the top and bottom if the image is large. The extra space (gray background color) is shown in the picture below.

How do I remove the extra space?

Imageview Extra Space
A few notes:

  1. This particular image is 890 x 589 and the screenshot was taken on a iphone 6S simulator.

  2. I am using UITableViewAutomaticDimension for automatic table cell height.

  3. There is no height constraint on the imageview so it can resize accordingly.

Thank you in advance.

like image 620
hmzfier Avatar asked Jul 20 '16 09:07

hmzfier


2 Answers

I had the same issue. This happens when the original image size is larger (in width and/or height) than the UIImageView that holds it and the image is resized with Aspect Fit to fit into the UIImageView.

Here, the image width is larger than can fit into the UIImageView so Aspect Fit resizes the image, keeping the original aspect ratio. If you read the image size (via watch or breakpoint or something) you will see that the image size is (for example) 600(h) x 800(w) (3:4 ratio). The UIImageView width is (e.g.) 320(w) thus the displayed image is scaled to 240(h) x 320(w) (keeping the 3:4 ratio). BUT the image width is still REALLY 600 x 800 and as there is no limitation on the UIImageView height the UIImageView size is 600 x 320 --> it sets the UIImageView height to the original image height (600) because it can.

My solution is this: (Swift 3)

Add a height constraint to the UIImageView in Main.storyboard and link it through an Outlet:

@IBOutlet weak var displayimage: UIImageView!
@IBOutlet weak var displayimageHeightConstraint: NSLayoutConstraint!

Then test whether the UIImageView is smaller (width) than the image it holds. If so, set the height constraint so that the UIImageView height:width ratio is the same as the image aspect ratio:

if displayimage.frame.size.width < (displayimage.image?.size.width)! {
    displayimageHeightConstraint.constant = displayimage.frame.size.width / (displayimage.image?.size.width)! * (displayimage.image?.size.height)!
}

The complementary operation is also possible if there is whitespace at the sides of the image due to an issue of resizing where the UIImageView height is limited and the width is set to the original image width.

@IBOutlet weak var displayimageWidthConstraint: NSLayoutConstraint!

if displayimage.frame.size.height < (displayimage.image?.size.height)! {
    displayimageWidthConstraint.constant = displayimage.frame.size.height / (displayimage.image?.size.height)! * (displayimage.image?.size.height)!
}
like image 84
Mick Avatar answered Nov 05 '22 00:11

Mick


The above answer doesn't work when using UITableViewAutomaticDimension.

In general the problem is that in the tableView function "cellForRowAt indexPath" tableView hasn't yet laid out cell and it's subviews.

So one solution to this problem is using a subclass of UITableView:

class MyUITableView: UITableView {

    // Makes real device cell width available in "cellForRowAt indexPath"
    override func dequeueReusableCell(withIdentifier identifier: String, for indexPath: IndexPath) -> UITableViewCell {
        let cell = super.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
        cell.frame.size.width = self.frame.size.width
        cell.layoutIfNeeded()
        return cell
    }
}

Now you can use any of the solutions in for instance the link in Md Rais' comment. As an example my own code:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ViewCell

    if let attach = eventsByDay[indexPath.section][indexPath.row].attachPhoto {
        let cellWidth = cell.attachPhoto.frame.size.width
        let scale = cellWidth / attach.size.width
        let size = CGSize(width: cellWidth, height: attach.size.height * scale)

        UIGraphicsBeginImageContextWithOptions(size, true, 0.0)             
        attach.draw(in: CGRect(origin: CGPoint.zero, size: size))
        cell.attachPhoto.image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    } else {
        cell.attachPhoto.image = nil
    }

    // ...
    return cell
}
like image 1
Hugo F Avatar answered Nov 05 '22 02:11

Hugo F