Where to add subViews that I want floating in an NSScrollView using AutoLayout?

Sam picture Sam · Dec 30, 2014 · Viewed 7.7k times · Source

I have several views that I need to have collaborate with a custom sub-class of NSScrollView I am making. One type of view needs to be fixed completely relative to the scrolling in the NSScrollView and another type needs to have its outer shell fixed in position relative to the scrolling but allow inner contents to scroll as the scrollview changes (like the column headers in a spreadsheet for example).

The following are the options for placement of these views within the view hierarchy AFAIK:

  1. SubView of NSScrollView (makes the most sense but I get the following error: *** +[NSLayoutConstraint constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:]: A multiplier of 0 or a nil second item together with a location for the first attribute creates an illegal constraint of a location equal to a constant. Location attributes must be specified in pairs)
  2. SubView of the superview of NSScrollView (this seems to work better but doesn't feel right from a design perspective given that I want my views to be part of the scrollView)

===

I have also read in more than one place online that I won't be able to use the Visual Format Language approach to setting up my constraints because floating constraints aren't set relative to the immediate superview. This is the clue that I am doing something wrong above because the 2nd approach could use VCL whereas the first would need to create NSLayoutConstraint manually.

===

The following is the Swift code that I have added to the initialiser of my NSScrollView subclass:

    topCorner = NSButton()
    topCorner.translatesAutoresizingMaskIntoConstraints = false
    topCorner.bezelStyle = NSBezelStyle.CircularBezelStyle  //.RecessedBezelStyle
    topCorner.setButtonType(NSButtonType.PushOnPushOffButton)
    topCorner.identifier = "topCorner"
    topCorner.title = "TC"
    self.addSubview(topCorner)

    thc = NSLayoutConstraint(item: self.topCorner, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.superview, attribute: NSLayoutAttribute.Left, multiplier: 1.0, constant: 0.0)
    self.addConstraint(thc)

    thc1 = NSLayoutConstraint(item: self.topCorner, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 36.0)
    self.addConstraint(thc1)

    thc2 = NSLayoutConstraint(item: self.topCorner, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.superview, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 0.0)
    self.addConstraint(thc2)

    thc3 = NSLayoutConstraint(item: self.topCorner, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 24.0)
    self.addConstraint(thc3)

Just to confuse things further, the error message that I get is only when I have the constraints thc and thc2 around in the code. (Experimented with commenting out different constraints to see which was causing the horrible error text.)

Answer

Sam picture Sam · Dec 30, 2014

The error message was caused by the fact that the relationship of self.superview had not been created at the time of adding the constraint.

A further error ensues because the two constraints thc & thc2 can't be added to the NSScrollView, they need to be added to its superview.

While the above still does not yield my desired result it gets rid of two errors that have arisen at runtime.