简体   繁体   中英

Add and layout subviews loaded from xib to a custom cell

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; ie 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

在此处输入图片说明

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

在此处输入图片说明

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 
}

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)
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM