1
votes

I'm struggling with a "small" issue. I have a UITableView who displays images loaded from a remote server. For each one of these images I have their width and height, so I use those values to calculate the aspect ratio.

I have a height constraint on the Image View where I'm displaying the image, so when I have the aspect ratio, I change this constraint before returning the cell on the delegate's method.

In order to calculate the aspect ratio I use the width of the Image View, and this one is calculated using constraints on IB. Like this.

enter image description here

The width I'm getting when I'm dequeuing the cell is the same set at IB. So my aspect ratio is wrong for a moment because is not using the proper width. Also, for a brief moment, the cell is using the height constraint set on IB before changing to the height constraint set on code. This is the method I use.

- (void)updateConstraint
{
  // get method has been created by me on a NSDictionary extension
  NSNumber *heightNumber = [self.articleItem.data get:kHeightKey];
  NSNumber *widthNumber = [self.articleItem.data get:kWidthKey];
  self.imageAspectRatio = 16/9;

  if (heightNumber != nil && widthNumber != nil) {
    self.imageWidth = widthNumber.floatValue;
    self.imageHeight = heightNumber.floatValue;
    self.imageAspectRatio = self.imageWidth / self.imageHeight;
  }

  self.imageHeightConstraint.constant = self.articleImageView.frame.size.width / self.imageAspectRatio;
}

For cell height I'm returning UITableViewAutomaticDimension.

I don't know if I'm doing all the calculation correctly and in the proper place (obviously not). Anyone can show the wight way? Thank you so much.

2
After updating your constraint, you should call layoutIfNeeded. Did you try that? - kchromik
Yes, and with that what I'm getting is the cell with the wrong height for a moment, before is updated and displayed in the proper height. - WedgeSparda

2 Answers

1
votes

Trust me, there's absolutely nothing "small" about this issue. If there were, then I'm probably just an idiot who thinks that can code. (Oh wait - maybe I am? Anyway :)

I don't have all the answers for you. What I know is that, I believe, I have what you want "more or less" working for me, so I'll try to help you out with the ideas that I've gathered either from the official documentation or from my many hours searching for answers on Stack Overflow itself.

enter image description here

First, some assumptions:

  1. You know the width of all your UITableViewCell's UIImageViews, from what I can gather looking at the picture you posted. Either they're "full bleed" (i.e. you use the full width of the screen, like in my screenshot) or you use some margins - the important thing is that you know the width, and what you dynamically want to change is the height.
  2. You mention this briefly, but again, it doesn't hurt to make sure. You're not waiting to fetch the image to set the height constraint. Instead, by the time you return from the tableView:cellForRowAtIndexPath: you've already updated your constraint. This is very important since AutoLayout likes to know the height of the cell before the user sees it.

Now, I believe your code looks OK. I'm sure you've looked at it through the debugger, done the math yourself, found out your height constraint's value is fine, but still, you can't get it to show properly as you want it to. You don't mention whether you're getting AutoLayout errors in your logs, so it's hard to tell exactly where your problem is, but I can point you towards the strategy that helped me a lot:

  1. When you learn of the height of a new UIImage you want to set, don't change your constraint directly. Instead, call setNeedsUpdateConstraints().
  2. Override updateConstraints(), and call super.updateConstraints() last. This is heavily emphasized in the official Documentation:

Always call the superclasses implementation as the last step of your updateConstraints method’s implementation.

  1. Before you call super.updateConstraints(), update your height constraint for the new UIImage. Why is this important? Besides this being the recommended way if you read the documentation, I believe doing this allows us to avoid the famous UIView-Encapsulated-Layout-Height AutoLayout errors which happen because the system will add constraints to fix the height of the UITableViewCell, and if we don't update our height constraint first, AutoLayout will be forced to break some constraint.

A couple of extra notes:

  1. Try playing around with your tableView's estimatedRowHeight property; set that to zero and see what happens. Or give it a more accurate value.
  2. Don't use heightForRowAtIndexPath() or related methods, they're incredibly slow, and you'll mess up your self-sizing cells. I recommend trying them out to see if playing with those values sheds some light to your AutoLayout, woes, but not for a product's release.
  3. Don't be disheartened. No matter what you might think, this is hard stuff.

I believe I can help you further if you provide us with more information (say screenshots, AutoLayout errors, etc.)

Best of luck!

0
votes

Perhaps reloading the tableView when the images are retrieved from the remote server would help. tableView.reloadData()