0

I created a xib file with a custom view that I want to display in a UITableViewCell.

The problem is: in the xib file, I set the width of the UIView to 600 (the size is Freeform) but I want to use constraints in order to obtain the correct width for every device.

I add this view in a UITableViewCell with addSubview() so I think that this view must be constraint to the view of the cell, is that right? How can I do this?

I add some code:

This my custom UIView related to the xib file:

class DownloadView: UIView, NSURLSessionDownloadDelegate{

///utilizzata per mostrare il nome del file in download
@IBOutlet var nomeFileInDownloadLabel: UILabel!

///utilizzata per mostrare la percentuale di download completato
@IBOutlet var quantitaScaricataLabel: UILabel!

///utilizzata per mostrare il download
@IBOutlet var progressView: UIProgressView!

var view : UIView!

private var downloadTask: NSURLSessionDownloadTask?

//Initialization
override init(frame: CGRect) {
    super.init(frame: frame)
    xibSetup()
}

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


//I setup the xib from here
func xibSetup() {
    view = loadViewFromNib()

    //if I set the following one the view is a square
    //view.frame = bounds

    // Make the view stretch with containing view
    view.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
    self.addSubview(view)
}

//I load the xib file
func loadViewFromNib() -> UIView {

    let bundle = NSBundle(forClass: self.dynamicType)
    let nib = UINib(nibName: "View", bundle: bundle)
    let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
    return view
}
//some code for other task 
...
}

In my UITableView in the method tableView(tableView:cellForRowAtIndexPath) I add the view:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("DownloadRootTVC_IDcell", forIndexPath: indexPath) as! DownloadTVCell

    //I get my custom view from an array
    let myView = self.listOfViewsDownlaod[indexPath.row]

    //I add the view to the cell
    cell.addSubview(myView)


    return cell
}

In this last method I think that I have to setup the constraint in order to fit my custom view in the UITableViewCell adapting it to the device width.

EDIT:

Since I want to adapt the width and the height of the subview to the cell I wrote this:

    let topConstraint = NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: cell, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 8)
    cell.addConstraint(topConstraint)

    let bottomConstraint = NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: cell, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 8)
    cell.addConstraint(bottomConstraint)

    let leftConstraint = NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: cell, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 20)
    cell.addConstraint(leftConstraint)

    let rightConstraint = NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.TrailingMargin, relatedBy: NSLayoutRelation.Equal, toItem: cell, attribute: NSLayoutAttribute.TrailingMargin, multiplier: 1, constant: 20)
    cell.addConstraint(rightConstraint)

The only one that doesn't work is the right one, the view continue over the screen. I also tried to use NSLayoutAttribute.Right or NSLayoutAttribute.RighMargin or to set the constant to a negative value, but doesn't work.

Ernesto Schiavo
  • 1,020
  • 2
  • 12
  • 33

2 Answers2

0

Your xib view doesn't have any constraints to it's superview when you add it as subview. You should create them programmatically. There is a great example. For instance, if you want place your view in center of superview and same size you can write next:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

  let cell = tableView.dequeueReusableCellWithIdentifier("cell")!
  let myView = UIView()
  myView.backgroundColor = UIColor.redColor()
  myView.translatesAutoresizingMaskIntoConstraints = false
  cell.addSubview(myView)
  let horizontalConstraint = NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: cell, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)
  cell.addConstraint(horizontalConstraint)

  let verticalConstraint = NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: cell, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0)
  cell.addConstraint(verticalConstraint)

  let widthConstraint = NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: cell, attribute: NSLayoutAttribute.Width, multiplier: 1, constant: 0)
  cell.addConstraint(widthConstraint)

  let heightConstraint = NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: cell, attribute: NSLayoutAttribute.Height, multiplier: 1, constant: 0)
  cell.addConstraint(heightConstraint)
  return cell
}

It will looks like this (blue - tableView, red - myView):

enter image description here

Community
  • 1
  • 1
rkyr
  • 3,131
  • 2
  • 23
  • 38
  • Thanks you for yuor help guy. Unfortunately with this constraints the app crash, I'm going to learn how to use them in order to use them properly. Thanks – Ernesto Schiavo Dec 23 '15 at 10:05
  • @Ernesto, ok, maybe you can show your error and I'll try to help? – rkyr Dec 23 '15 at 19:51
  • I get this error: `Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[NSLayoutConstraint constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:]: Unknown layout attribute' ` What do you think? Thanks you very much!! – Ernesto Schiavo Dec 29 '15 at 21:40
  • @Ernesto, yeah, sorry. My fault. NSLayoutAttribute for width and height constraints shouldn't be .NotAnAttribute. I update my answer. – rkyr Dec 29 '15 at 22:04
  • ok thanks! I'll try the new code this evening. I'll let you know about it – Ernesto Schiavo Dec 30 '15 at 08:30
  • I don't know what's wrong but it doesn't work.. please see my edit in the post! Thanks – Ernesto Schiavo Dec 30 '15 at 19:58
  • @Ernesto I also don't know. I update answer with tested example and screenshot. If it doesn't help please post actual code from cellForRow function. – rkyr Dec 30 '15 at 20:42
  • your code works well in a new project. So I think the problem may occur while loading the nib, what do you think about the method "xibSetup()" (you can see it in the question)? Maybe I have to set up constraints also to that view.. – Ernesto Schiavo Dec 30 '15 at 21:29
  • finally I find the solution! See answer below! Thanks you!! – Ernesto Schiavo Dec 30 '15 at 21:49
0

Finally I find the issue:

the problem is in the xibSetup() method because I load the xib but I don't set the constraints! So my new method is:

func xibSetup() {
    let myView = loadViewFromNib()

    myView.translatesAutoresizingMaskIntoConstraints = false

    self.addSubview(myView)

    let leading = NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: myView.superview, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0)
    self.addConstraint(leading)

    let bottom = NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: myView.superview, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)
    self.addConstraint(bottom)

    let trailing = NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: myView.superview, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0)
    self.addConstraint(trailing)

    let top = NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: myView.superview, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
    self.addConstraint(top)

}

This solved my problem.

Ernesto Schiavo
  • 1,020
  • 2
  • 12
  • 33