0

I have a custom cell 'CustomCell' that I wish to compose based on a custom data element. I am trying to add subviews to CustomCell but for those subviews loaded from a xib (https://stackoverflow.com/a/26326006/3546621), I can't figure out how to layout them into the cell's contentView; i.e programmatically setting their frame nor adding constraints seem to work. ( CustomCell has no xib attached, every subviews is loaded programmatically. Some of these subview are loaded from xib.)

For example, here is my custom cell. It has two subviews, a yellowView initialized with UIView(frame: CGRect()) and right below a blueView initialized with UIView.fromNib.

This is BlueView.xib

enter image description here

I am not succeeding at placing blueView below yellowView, instead I have the blueView being stacked on top of the yellowView:

enter image description here

class CustomCell: UITableViewCell {

  let yellowView: UIView = UIView()
  let blueViewFromXib: BlueView = UIView.fromNib()

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

  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
  }

  fun configureForData(custom: Custom){

    yellowView.backgroundColor = UIColor.yellowColor()
    yellowView.translatesAutoresizingMaskIntoConstraints = false
    contentView.addSubview(yellowView)

    blueView.translatesAutoresizingMaskIntoConstraints = false
    contentView.addSubview(blueView)

    layoutIfNeeded()
  }

  override func layoutSubviews() {
    super.layoutSubviews()
    let height = NSLayoutConstraint(item: contentView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 80)
    contentView.translatesAutoresizingMaskIntoConstraints = false
    contentView.addConstraint(height)

    yellowView.frame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: 40)

    // I want to add the blueView at the bottom of the yellowView

    // Option 1: not working
    blueView.frame = CGRect(x: 0, y: 40, width: contentView.frame.width, height: 40)

    // Option 2: not working
    let top = NSLayoutConstraint(item: blueView, attribute: .Top, relatedBy: .Equal, toItem: contentView, attribute: .Top, multiplier: 1, constant: 40)
    let bottom = NSLayoutConstraint(item: blueView, attribute: .Bottom, relatedBy: .Equal, toItem: contentView, attribute: .Bottom, multiplier: 1, constant: 0)
    let leading = NSLayoutConstraint(item: blueView, attribute: .Leading, relatedBy: .Equal, toItem: contentView, attribute: .Leading, multiplier: 1, constant: 0)
    let trailing = NSLayoutConstraint(item: blueView, attribute: .Trailing, relatedBy: .Equal, toItem: contentView, attribute: .Trailing, multiplier: 1, constant: 0)
    contentView.addConstraints([top, bottom, leading, trailing])
  }
}

class BlueView: UIView {
  // the project includes a BlueView.xib which is simply a UIView whose background color is blue
}

View Controller

override func viewDidLoad(){
  super.viewDidLoad()
  tableView.delegate = self
  tableView.datasource = self
  tableView.rowHeight = UITableViewAutomaticDimension
  tableView.estimatedRowHeight = 80
  tableView.registerClass(CustomCell.self, forCellReuseIdentifier: "CustomCell")
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
  let custom = customs[indexPath.row]
  let cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomCell
  cell.configureForData(custom)
  return cell 
}
Community
  • 1
  • 1
user3546621
  • 357
  • 3
  • 12
  • If you're using a nib, you can layout the views there. Is there a reason you want to do it manually? – GetSwifty Jun 27 '16 at 15:38
  • @PEEJWEEJ I know how to layout the subviews themselves ( i.e the subviews of the nib loaded subviews). But I am no succeeding at laying out the subviews into the cell's content view. – user3546621 Jun 27 '16 at 16:15
  • You can add the views to the cell in the nib and connect them with IBOutlets – GetSwifty Jun 27 '16 at 18:29
  • BTW, your code for setting the frames in layoutSubviews is setting them to a new UIView...which shouldn't even compile – GetSwifty Jun 27 '16 at 18:31
  • @PEEJWEEJ please check the code. The custom cell has no xib. I want to build it programmatically. Only some of the subviews that will compose the final cell are loaded from a xib – user3546621 Jun 27 '16 at 18:32
  • ah sorry, misunderstood the question – GetSwifty Jun 27 '16 at 18:34

1 Answers1

0

A couple things to be aware of

  1. In layoutSubviews you shouldn't be adding/removing constraints that don't change. If you set the constraints, the default implementation (super.layoutSubviews()) will adjust the size/layout based on the constraints.

  2. If you set constraints, they override any frames that were set.

  3. blueView.frame = UIView(frame: CGRect(x: 0, y: 40, width: contentView.frame.width, height: 40)) shouldn't even compile. You're setting blueView's frame (a CGRect) to a new instance of UIView.

Regardless, it appears you're using layoutConstraints for blueView, and manually setting the frame for yellowView. I'm guessing if you use one of these you will be able to work out what's going on.

To simplify things, try setting your subViews to optionals:

let yellowView: UIView?
let blueViewFromXib: BlueView?

Then comment out layoutSubviews, and use this:

func configureForData(custom: Custom){

    if yellowView == nil {
        yellowView = UIView(frame: CGRect(x: 0, y: 0, width: self.frame.width, height: 40))
        yellowView?.backgroundColor = UIColor.yellowColor()
        self.addSubview(yellowView)
    }
    if blueView == nil {
        blueView = BlueView.fromNib()
        blueView?.frame = CGRect(x: 0, y: 40, width: self.frame.width, height: 40)
        self.addSubview(blueView)
    }
}
GetSwifty
  • 7,568
  • 1
  • 29
  • 46