0

I am learning auto layout in iOS8 by using SnapKit . I got lot of errors while applying constraints to cell subviews. below is the code used as subview to cell.contentview.

 class FanFeedDynamicCellView: UIView{
var fanProfileImageView:UIImageView?
var fanNameLabel:UILabel?
var contentLabel:UILabel?
var thumbnailImageView:UIImageView?
var spacierView_FanProfile:UIView?

override init(frame: CGRect) {
    super.init(frame : frame)
    setupViewProperties()
}


convenience init () {
    self.init(frame:CGRect.zero)
}

required init(coder aDecoder: NSCoder) {
    fatalError("This class does not support NSCoding")
}


func setupViewProperties()
{

    //1 add fanProfileImageView
    fanProfileImageView = UIImageView()
    fanProfileImageView!.image = UIImage(named: "avatar")
   // setBorder(fanProfileImageView!)
    self.addSubview(fanProfileImageView!)

    //2 add Fan Name Label 
    fanNameLabel = UILabel()
    fanNameLabel!.lineBreakMode = .ByTruncatingTail
    fanNameLabel!.numberOfLines = 1
    fanNameLabel!.textAlignment = .Left
    fanNameLabel!.textColor = UIColor.blackColor()
    fanNameLabel!.backgroundColor = UIColor(red: 0, green: 0, blue: 1, alpha: 0.1) // light blue
    self.addSubview(fanNameLabel!)

    //3 add ContentLabel
    contentLabel = UILabel()
    contentLabel!.lineBreakMode = .ByTruncatingTail
    contentLabel!.numberOfLines = 0
    contentLabel!.textAlignment = .Left
    contentLabel!.textColor = UIColor.darkGrayColor()
    contentLabel!.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 0.1) // light red
    self.addSubview(contentLabel!)

    //4 add Thumbnail View
    thumbnailImageView = UIImageView()
   // setBorder(thumbnailImageView!)
    thumbnailImageView!.contentMode = .ScaleAspectFit
    thumbnailImageView!.image = UIImage(named: "avatar")
    self.addSubview(thumbnailImageView!)


     updateFonts()
    //Constraints for subviews
    //setupConstraintsForProperties()
}


func updateFonts()
{
    fanNameLabel!.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
    contentLabel!.font = UIFont.preferredFontForTextStyle(UIFontTextStyleCaption2)
}


override func updateConstraints()
{
    let padding:UIEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10)


    fanProfileImageView!.snp_makeConstraints { (make) -> Void in
        make.top.equalTo(self.snp_top).offset(padding.top)
        make.left.equalTo(self.snp_left).offset(padding.left)
        make.width.height.equalTo(60.0)
        make.bottom.lessThanOrEqualTo(thumbnailImageView!.snp_top).offset(-padding.bottom)
    }

    fanNameLabel!.snp_makeConstraints { (make) -> Void in
        make.top.equalTo(self.snp_top).offset(padding.top)
        make.left.equalTo(fanProfileImageView!.snp_right).offset(padding.right)
        make.right.equalTo(self.snp_right).offset(-padding.right)
      //  make.bottom.lessThanOrEqualTo(contentLabel!.snp_top).offset(-padding.top)
        make.height.equalTo(20)
    }

    contentLabel!.snp_makeConstraints { (make) -> Void in
        make.top.equalTo(fanNameLabel!.snp_bottom).offset(padding.top)
        make.left.equalTo(fanProfileImageView!.snp_right).offset(padding.left)
        make.right.equalTo(self.snp_right).offset(-padding.right)
       // make.bottom.lessThanOrEqualTo(thumbnailImageView!.snp_top).offset(-padding.bottom)
       // make.height.greaterThanOrEqualTo(20)
    }

    thumbnailImageView!.snp_makeConstraints { (make) -> Void in
        make.top.greaterThanOrEqualTo(contentLabel!.snp_bottom).offset(padding.top)
       // make.left.equalTo(padding.left)
        make.bottom.lessThanOrEqualTo(-padding.bottom)
        make.height.greaterThanOrEqualTo(20)            
        make.centerX.equalTo(self.snp_centerX) }
    super.updateConstraints()
}



func setBorder(cView:UIView) -> UIView
{
    let cLayer : CALayer = cView.layer
    cLayer.borderColor = UIColor.redColor().CGColor
    cLayer.borderWidth = 0.5
    return cView
}

override func layoutSubviews() {
    super.layoutSubviews()
    fanNameLabel!.contentHuggingPriorityForAxis(.Vertical)
    fanNameLabel!.contentCompressionResistancePriorityForAxis(.Vertical)

    contentLabel!.contentHuggingPriorityForAxis(.Vertical)
    contentLabel!.contentCompressionResistancePriorityForAxis(.Vertical)

}

The output would be the same as attached image image. here we use on profile Image in LeftSide . User Name on top of label. Content label marked in light orange color would be the multiline. below this i attached the ImageView. when i scroll the tableview the height of the cell is unpredictable(layout changes automatically). would help me to correct the constraint to achieve the this output. For first launch the multiline cell would be in One line . once i goes to invisible the come again visible it adopt for full label content

Lorenzo
  • 3,293
  • 4
  • 29
  • 56
Srini
  • 387
  • 1
  • 13
  • 27

1 Answers1

1

You add more constraints than you had to. Also you don't really need to use contentHuggingPriority and contentCompressionResistance to achieve what you want.

This is how to make it work:

FanFeedDynamicCellView

class FanFeedDynamicCellView: UIView {
    let fanProfileImageView = UIImageView()
    let fanNameLabel = UILabel()
    let contentLabel = UILabel()
    let thumbnailImageView = UIImageView()

    override init(frame: CGRect) {
        super.init(frame: frame)

        setupViews()
        setupConstraints()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setupViews() {
        fanProfileImageView.image = UIImage(named: "avatar")
        addSubview(fanProfileImageView)

        fanNameLabel.lineBreakMode = .ByTruncatingTail
        fanNameLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
        fanNameLabel.numberOfLines = 1
        fanNameLabel.textAlignment = .Left
        fanNameLabel.textColor = UIColor.blackColor()
        fanNameLabel.backgroundColor = UIColor(red: 0, green: 0, blue: 1, alpha: 0.1) // light blue
        addSubview(fanNameLabel)

        contentLabel.lineBreakMode = .ByTruncatingTail
        contentLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleCaption2)
        contentLabel.numberOfLines = 0
        contentLabel.textAlignment = .Left
        contentLabel.textColor = UIColor.darkGrayColor()
        contentLabel.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 0.1) // light red
        addSubview(contentLabel)

        thumbnailImageView.contentMode = .ScaleAspectFit
        thumbnailImageView.image = UIImage(named: "thumbnail.jpg")
        thumbnailImageView.backgroundColor = UIColor(red: 0, green: 1, blue: 0, alpha: 0.2) // light green
        addSubview(thumbnailImageView)
    }

    func setupConstraints() {
        let padding:UIEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10)

        fanProfileImageView.snp_makeConstraints { (make) -> Void in
            make.top.equalTo(padding.top)
            make.left.equalTo(padding.left)
            make.width.height.equalTo(60)
            make.bottom.lessThanOrEqualTo(-padding.bottom)
        }

        fanNameLabel.snp_makeConstraints { (make) -> Void in
            make.top.equalTo(fanProfileImageView)
            make.left.equalTo(fanProfileImageView.snp_right).offset(padding.right)
            make.right.equalTo(-padding.right)
        }

        contentLabel.snp_makeConstraints { (make) -> Void in
            make.top.equalTo(fanNameLabel.snp_bottom).offset(padding.top)
            make.left.right.equalTo(fanNameLabel)
        }

        thumbnailImageView.snp_makeConstraints { (make) -> Void in
            make.top.greaterThanOrEqualTo(contentLabel.snp_bottom).offset(padding.top)
            make.top.greaterThanOrEqualTo(fanProfileImageView.snp_bottom).offset(padding.top)
            make.left.equalTo(fanProfileImageView)
            make.right.equalTo(fanNameLabel)
            make.bottom.equalTo(-padding.bottom)
        }
    }
}

I don't know why you created a UIView subclass instead of a UITableViewCell subclass for this, but I kept it that way and just added this view to a custom UITableViewCell subclass

FanFeedTableViewCell

This only adds the FanFeedDynamicCellView to its contentView:

class FanFeedTableViewCell: UITableViewCell {
    let fanFeedView = FanFeedDynamicCellView()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: .Subtitle, reuseIdentifier: reuseIdentifier)
        setupView()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setupView() {
        contentView.addSubview(fanFeedView)

        fanFeedView.snp_makeConstraints { (make) -> Void in
            make.edges.equalTo(contentView)
        }
    }
}

And that's it! Now just use this FanFeedTableViewCell in your UITableView and set the texts and images in cellForRowAtIndexPath.

Don't forget to do this with your table view to enable dynamic cell heights:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 100 // or whatever your estimated row height is. This does not have to be precise

This is how it looks:

enter image description here

joern
  • 27,354
  • 7
  • 90
  • 105