1

I have a cell with image pinned to left-top-right of cell. Other constraints related to image.

enter image description here

Here is image height constraint:

enter image description here

Here is my data setter:

import UIKit
import Kingfisher

class WorkoutSectionCollectionViewCell: UICollectionViewCell {

@IBOutlet weak var colorLine: UIView!
@IBOutlet weak var workoutName: UILabel!
@IBOutlet weak var widthConstraint: NSLayoutConstraint!
@IBOutlet weak var workoutDescription: UILabel!
@IBOutlet weak var parametersStackView: UIStackView!
@IBOutlet weak var exercisesIcon: UIImageView!
@IBOutlet weak var exercisesLabel: UILabel!
@IBOutlet weak var musclesIcon: UIImageView!
@IBOutlet weak var musclesLabel: UILabel!
@IBOutlet weak var workoutImage: UIImageView!

var workout: Workout? {
    didSet {
        // Get image form backend
        if let imageUrl = workout?.workoutImage?.imageUrl {
            let resource = ImageResource(downloadURL: URL(string: imageUrl)!, cacheKey: imageUrl)
            workoutImage.kf.setImage(with: resource)
            workoutImage.isHidden = false
        } else {
            workoutImage.isHidden = true
        }

        if let workoutKind = workout?.workoutKind {
            switch workoutKind {
            case "силовая": colorLine.backgroundColor = Colors.colorCadmiumOrange
            case "фитнес": colorLine.backgroundColor = Colors.colorGreen
            case "кардио": colorLine.backgroundColor = Colors.colorBlueDeFrance
            case "HIIT": colorLine.backgroundColor = Colors.colorCarminePink
            default:
                colorLine.backgroundColor = Colors.colorClear
            }
        }

        workoutName.text = workout?.workoutName

        if let workoutDesc = workout?.workoutDesc {
            workoutDescription.text = workoutDesc.html2String
        }

        if let numberOfExercises = workout?.workoutExercises?.count {
            exercisesLabel.text = "\(numberOfExercises) " + pluralForm(number: numberOfExercises, forms: ["упражнение", "упражнения", "упражнений"])
        }

        var workoutMuscles: [String] = []
        workout?.workoutExercises?.forEach({ (exercise) in
            workoutMuscles.append((exercise as! Exercise).mainMuscle!)
        })
        musclesLabel.text = Set(workoutMuscles).joined(separator: ", ").lowercased()
    }
}

override func awakeFromNib() {
    super.awakeFromNib()

    // Initialization code
    self.contentView.translatesAutoresizingMaskIntoConstraints = false
    let screenWidth = UIScreen.main.bounds.size.width
    widthConstraint.constant = screenWidth - 20
    self.layer.cornerRadius = 3
    workoutName.textColor = Colors.colorPaynesGrey
    workoutDescription.textColor = Colors.colorDimGray
    exercisesLabel.textColor = Colors.colorSilver
    musclesLabel.textColor = Colors.colorSilver
    musclesIcon.tintColor = Colors.colorSilver
    exercisesIcon.tintColor = Colors.colorSilver
}

I use KingFisher library to get image from backend by REST Api.

The problem is some cells have image and then everything is ok, but some cells haven't image and then empty space appear.

enter image description here

I would like to hide empty space if no image and shrink cell height to fit content. How I can do it?

SOLVED: Here is how I solve it wit help of @Fangming Ning

I add an outlet for image height:

@IBOutlet weak var imageHeightConstraint: NSLayoutConstraint!

Then set window width and insets (by 10 left & right):

let screenWidth = UIScreen.main.bounds.size.width
let screenInsets: CGFloat = 20

And in didSet add following code:

if let imageUrl = workout?.workoutImage?.imageUrl {
            let resource = ImageResource(downloadURL: URL(string: imageUrl)!, cacheKey: imageUrl)
            workoutImage.kf.setImage(with: resource)
            // Set image height if image exists
            imageHeightConstraint.constant = (screenWidth - screenInsets) * 0.666
        } else {
            // Set 0 if no image
            imageHeightConstraint.constant = 0
        }

And in IB image constraint looks like this: enter image description here

andrey
  • 1,136
  • 9
  • 19

2 Answers2

1

If your image comes from an async server call, there its not a good idea to shrink the cell when there is no image in the call back. If you do so, your table view will glitch a lot and the user experience will be bad.

Instead, in your call to retrieve text in the first place, you need to check if there is image or not. Then, hide the image view on the first place instead of leaving the space at first and then check image existence.

To do this, in your server call, say you include a key saying hasImage in the returned JSON respond. We also need to set up the cell so that the image view on top has a height constraint. The text view on bottom needs to have constraint saying padding top. In this way, when you set your image view height to 0, your text view will automatically moves up to shrink a cell.

First, give your height constraint an identifier so that we can change it from code. It looks like this

enter image description here

Now, in your cellForRow, you can do something like

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "ImageCell") as! ImageCell
    if dataArray[indexPath.row].hasImage {
        //add image
    } else {
        let filteredConstraints = cell.imgView.constraints.filter { $0.identifier == "imgTxtCellImgHeight" }
        if let heightConstraint = filteredConstraints.first {
            heightConstraint.constant = 0
        }
    }
    return cell
}
Fangming
  • 24,551
  • 6
  • 100
  • 90
  • This way I have to create two different cells with image and without image. I think it is not the best solution. – andrey Jul 02 '17 at 10:49
  • @andrey Updated – Fangming Jul 02 '17 at 10:58
  • It works with `constant` value! But I don't use `constant` to set image height, I use `multiplier`. I needs to have same aspect ratio every time. I add image describing my constraint. – andrey Jul 02 '17 at 11:42
0

make a outlet of your workoutImage height constraint in your cell class

@IBOutlet weak var workoutImageHeight: NSLayoutConstraint!

and in your didSet:-

didSet {
        // Get image form backend
        if let imageUrl = workout?.workoutImage?.imageUrl {
            let resource = ImageResource(downloadURL: URL(string: imageUrl)!, cacheKey: imageUrl)
            workoutImage.kf.setImage(with: resource)
            workoutImageHeight.constant = 200 // make this value as you want
        } else {
            workoutImageHeight.constant = 0
        }
}

and add this UICOllectionViewDelegateFlowLayout Method into your controller

func collectionView(_ collectionView: UICollectionView,layout collectionViewLayout: UICollectionViewLayout, 
               sizeForItemAt indexPath: IndexPath) -> CGSize{
      // replace the name of workoutArray from your array..
      if let imageUrl = workoutArray[indexPath.item]?.workoutImage?.imageUrl {              
           // replace height as you want  
           return CGSize(width:collectionView.bounds.width , height:400)
        } else {
           return CGSize(width:collectionView.bounds.width , height:200) 
        }
}
Irshad Ahmad
  • 1,363
  • 11
  • 17