JohnDole
JohnDole

Reputation: 555

Setting up different layouts for one cell, depending on its content

In an UITableViewCell, I have an UIView container, which contains a UIImageView on top and an UILabel on the bottom. When the UILabel does not contain text, I want to remove the UILabel and resize the UImageView to the bottom of my UIView container.

In my TableViewCell, I have this:

        let x = imageViewPostPreview.bottomAnchor.constraint(equalTo: viewPreviewOverlay.topAnchor, constant: 0)

        if postText == "" {
            x.isActive = true
            imageViewPostPreview.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMinXMaxYCorner]
            self.layoutSubviews()
            self.layoutIfNeeded()

        } else if postText != "" {
            x.isActive = false
            imageViewPostPreview.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]
            self.layoutSubviews()
            self.layoutIfNeeded()
            }
        }

This piece of code works on when the initial UITableViewCell is loaded, but when I scroll my UITableView, the cell loses the initial layout.

How do I setup the layout correctly, so the layout is kept on scroll?

Edit:

Initial cell, which is correct:

enter image description here

After scrolling, incorrect layout:

enter image description here

Upvotes: 0

Views: 141

Answers (2)

Nare Muradyan
Nare Muradyan

Reputation: 91

A way you can have the cell calculate its size automatically, is to have constraints set inside the cell view for all directions on vertical axis. So, in your case the image view will have top, leading and trailing set to superview, and bottom to the label. The label will have leading and bottom to superview, and the top will be to the image view you set. It's important to set for vertical axis, since for table view we need it to calculate the height. This way the table view will know what to expect and can set height automatically.

After that you set tableView.rowHeight = UITableView.automaticDimension. Or you can also set in the delegate method.

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return UITableView.automaticDimension }

After all this is in place, you will only need to give the right values to the cell subviews(in this case set image and text). You can do this inside cell for row function. A sample code will look something like this.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath)
    let model = self.models[indexPath.row]
    cell.imageViewPostPreview.image = model.image ?? nil
    cell.postText.text = model.text ?? nil
    return cell
    }

This should work without any further need to calculate constraints and calling layouts to update. Hope this helps! You can also check this question.

Upvotes: 0

Jawad Ali
Jawad Ali

Reputation: 14397

Add this to prepareToReuse method

 override func prepareForReuse() {
    super.prepareForReuse()


  let x = imageViewPostPreview.bottomAnchor.constraint(equalTo: viewPreviewOverlay.topAnchor, constant: 0)

    if postText.isEmpty {
      x.isActive = true
      imageViewPostPreview.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMinXMaxYCorner]


  } else  {
      x.isActive = false
      imageViewPostPreview.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]

      }

   self.layoutIfNeeded()
  }

Note: Dont call layoutSubview directly ... always try to call layoutifNeeded or setNeeedsLayout

Upvotes: 0

Related Questions