how to instantiate an NSLayoutConstraint in swift? (Xcode 6.1.1) - xcode

I'm getting an error "Extra argument in call" pointing at the first parameter.
let imageView = UIImageView()
let imageHeight = 10.0
let heightConstraint = NSLayoutConstraint(imageView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .Height, multiplier: 1.0, constant: imageHeight)
I've also tried using item: imageView,..., but I get the same error.

I think the problem is that imageHeight is double, but the constructor expects a CGFloat, so try
let imageHeight: CGFloat = 10.0
and looks like there is one more little thing:
NSLayoutConstraint(item: imageView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .Height, multiplier: 1.0, constant: imageHeight)
you left the item before imageView, but you've mentioned that.

Related

NSScrollView truncate text and no scroll bar

I'm having difficult to set up NSScrollView for my text file display.
Defined a window with proper size:
......
let contentRect = NSMakeRect(0.0, 0.0, 800, 600)
let styleMask:NSWindow.StyleMask = [.titled, .closable, .miniaturizable, .resizable]
let window = NSWindow(contentRect:contentRect, styleMask:styleMask, backing:.buffered, defer:true)
window.minSize = NSMakeSize(800.0, 600.0)
window.isReleasedWhenClosed = false
window.tabbingMode = .disallowed
window.makeKeyAndOrderFront(nil)
window.center() // Wait until after makeKeyAndOrderFront so the window sizes properly first
window.title = NSLocalizedString("GCode File", comment:"GCode File window")
......
set up scrollview and put it into windows and then set up window constraints:
......
let scrollView = NSScrollView(frame: (window.contentView?.frame)!)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.borderType = .noBorder
scrollView.backgroundColor = NSColor.gray
scrollView.hasVerticalScroller = true
window.contentView?.addSubview(scrollView)
window.contentView?.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[scrollView]|", options: [], metrics: nil, views: ["scrollView": scrollView]))
window.contentView?.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[scrollView]|", options: [], metrics: nil, views: ["scrollView": scrollView]))
......
set up clipview and put clipview as scrollview's content view and then configure scrollview and clipview's constraints:
......
let clipView = NSClipView()
clipView.translatesAutoresizingMaskIntoConstraints = false
scrollView.contentView = clipView
scrollView.addConstraint(NSLayoutConstraint(item: clipView, attribute: .left, relatedBy: .equal, toItem: scrollView, attribute: .left, multiplier: 1.0, constant: 0))
scrollView.addConstraint(NSLayoutConstraint(item: clipView, attribute: .top, relatedBy: .equal, toItem: scrollView, attribute: .top, multiplier: 1.0, constant: 0))
scrollView.addConstraint(NSLayoutConstraint(item: clipView, attribute: .right, relatedBy: .equal, toItem: scrollView, attribute: .right, multiplier: 1.0, constant: 0))
scrollView.addConstraint(NSLayoutConstraint(item: clipView, attribute: .bottom, relatedBy: .equal, toItem: scrollView, attribute: .bottom, multiplier: 1.0, constant: 0))
......
setup nstextview and load file content into nstextview:
......
var textView: NSTextView!
var textStorage: NSTextStorage!
textStorage = NSTextStorage()
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(containerSize: window.contentView!.bounds.size)
layoutManager.addTextContainer(textContainer)
textView = NSTextView(frame: window.contentView!.bounds, textContainer: textContainer)
textView.isEditable = true
textView.isSelectable = true
textView.textStorage?.append(file)
scrollView.documentView = textView
......
Then I run the application, I got windows and content rendering up as:
What's wrong? I don't see the full text (truncated) that load from file and there is no vertical scroll bar shows as well. I believe there are some thing missed in my constraints configuration.
If any one have the experience, please advise!

Autolayout not working - Child View Size always 0 while it should have same size as Superview

I have an odd behaviour for NSView in regards to autolayout.
I am bounding my only child view to the superview's size by this code:
func fillHorizontal() {
guard let sv = self.superview else {
assert(false)
return
}
self.translatesAutoresizingMaskIntoConstraints = false
sv.addConstraint(NSLayoutConstraint(
item: self, attribute: .width,
relatedBy: .equal, toItem: sv,
attribute: .width, multiplier: 1, constant: 0))
sv.addConstraint(NSLayoutConstraint(
item: self, attribute: .left,
relatedBy: .equal, toItem: sv,
attribute: .left, multiplier: 1, constant: 0))
}
func fillVertical() {
guard let sv = self.superview else {
assert(false)
return
}
self.translatesAutoresizingMaskIntoConstraints = false
sv.addConstraint(NSLayoutConstraint(
item: self, attribute: .height,
relatedBy: .equal, toItem: sv,
attribute: .height, multiplier: 1, constant: 0))
sv.addConstraint(NSLayoutConstraint(
item: self, attribute: .top,
relatedBy: .equal, toItem: sv,
attribute: .top, multiplier: 1, constant: 0))
}
func bindFrameToSuperviewBounds() {
fillHorizontal()
fillVertical()
}
The resulting constraints are as I would expect
However, I was never able to see the child view (GraphView). When started debugging/tweaking the setFrameSize function in child view like this:
override func setFrameSize(_ newSize: NSSize) {
if let superSize = self.superview?.frame.size, newSize == superSize { //this is quite dodgy. Not sure why I get too many zero-sized initiations.
super.setFrameSize(newSize)
}
}
then it became clear that all the layout engine is always calculating a size 0 for the child view.
How can that be? Who can tell me my mistake? Many thanks in advance!
Kamil Szostakowski asked the right question. Autolayout doesn't work well with manual size setting. I need to set NSView frame size through constraints.
Thanks Kamil.

Shadow is drawn in "main" Storyboard but not in any other storyboard

I try to write my own comboBox as NSComboBox does not has features I need.
So, I subclassed an NSTextField and monitor the textinput and depending of the stringValue a TableView will get it's data.
So when the TableView should be displayed the TextFields superview will add the NSScrollView and adjust it's height and so on.
All of that works fine.
What goes not so well is the DropShadow.
So, I create a new Xcode-Project an in the main.Storyboard add a NSTextField and change the class to my Subclass.
As soon as I type text the TableView appears and has a the dropShadow.
Next I create a new Storyboard, add a new WindowController and do the same steps as in the main.Storyboard: Adding an NSTextField, change the class to my subclass.
Now I add a Button in the main.Storyboard which has an action to present the new Storyboard.
In the new storyboard the textfield and tableView behave as expected except that the TableView/ScrollView does not have any shadow.
Even when I change MainInterface in the Generals tab to the new Storyboard, no DropShadow for the TableView.
The Settings in the IB for both Storyboards look equal.
So, any hint how I can fix this?
Here is the code for adding and displaying the scrollView:
self.scrollView = NSScrollView(frame: NSRect.zero)
self.scrollView!.documentView = self.tableView
self.scrollView!.translatesAutoresizingMaskIntoConstraints = false
self.scrollViewHeightConstraint = NSLayoutConstraint(item: self.scrollView!, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100)
let topConstraint = NSLayoutConstraint(item: self.scrollView!, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: 0)
let widthConstraint = NSLayoutConstraint(item: self.scrollView!, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.width, multiplier: 1, constant: 0)
let leadinghConstraint = NSLayoutConstraint(item: self.scrollView!, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.leading, multiplier: 1, constant: 0)
superview.addSubview(self.scrollView!)
superview.addConstraints([self.scrollViewHeightConstraint!,topConstraint,widthConstraint,leadinghConstraint])
let dropShadow = NSShadow()
dropShadow.shadowColor = NSColor.darkGray
dropShadow.shadowOffset = NSMakeSize(0, 10.0)
dropShadow.shadowBlurRadius = 3.0
self.scrollView!.wantsLayer = true
self.scrollView!.shadow = dropShadow
After a quick test … I found the "problem".
For the new ViewControllers view I had to set
self.view.wantsLayer = true

Swift 3 | Adding constraints programmatically doesn't center my subview

I try to write an UIImageView extension which display an ActivityIndicator in the middle of my ImageView, I tried the following, note that my ImageViews have a constraint on height (100) and width (100) :
public extension UIImageView {
public func downloadedFrom(url: URL) {
let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
activityIndicator.startAnimating()
let leftSpaceConstraint = NSLayoutConstraint(item: activityIndicator, attribute: NSLayoutAttribute.left, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.left, multiplier: 1, constant: 40)
let topSpaceConstraint = NSLayoutConstraint(item: activityIndicator, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.top, multiplier: 1, constant: 40)
let widthConstraint = NSLayoutConstraint(item: activityIndicator, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 20)
let heightConstraint = NSLayoutConstraint(item: activityIndicator, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 20)
self.addSubview(activityIndicator)
self.addConstraints([leftSpaceConstraint, topSpaceConstraint, widthConstraint, heightConstraint])
}
}
I also tried to set leadingSpaceConstraint / trailingSpaceConstraint / horizontalConstraint / verticalConstraint but my code has no effect, every constraints I set doesn't do change anything. My activityIndicator stay at the top left like this :
I don't understand why ? The method "downloadedFrom" is called in the viewDidLoad like this :
myImageView.downloadedFrom(url: imageUrl)
Where did I go wrong ? TY
You are placing your imageView on the top of parent UIView from the left side. It needs to be depending on coordinates of the middle of parent UIImageView for x-axis and y-axis. And also, set translatesAutoresizingMaskIntoConstraints to false. Look at the code below:
public extension UIImageView {
public func downloadedFrom(url: URL) {
let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
activityIndicator.startAnimating()
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
let leftSpaceConstraint = NSLayoutConstraint(item: activityIndicator, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0)
let topSpaceConstraint = NSLayoutConstraint(item: activityIndicator, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0)
let widthConstraint = NSLayoutConstraint(item: activityIndicator, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 20)
let heightConstraint = NSLayoutConstraint(item: activityIndicator, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 20)
self.addSubview(activityIndicator)
self.addConstraints([leftSpaceConstraint, topSpaceConstraint, widthConstraint, heightConstraint])
}
}

Mac OS X use auto layout with view controller and allow window resize

I'm trying to add a view to fill the entire window in Mac OS X like so:
func viewDidLoad() {
sparkView = NSView(frame: CGRectMake(0, 0, 600,400))
self.view.addConstraint(NSLayoutConstraint(item: sparkView!, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: sparkView!, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: sparkView!, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: sparkView!, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0))
sparkView?.contentCompressionResistancePriorityForOrientation(NSLayoutConstraintOrientation(rawValue: 499)!)
}
Why does this constrain the window size? If i do this I can't make the window bigger. I want sparkView to always fill the window. For context, this is created in the view controller that comes inside the NSWindow in storyboard.
I tried not setting the frame of sparkView, but then the window just collapses and there is no height at all.
Whenever you create a view programmatically and want to use auto layout to position it, you need to turn its translatesAutoresizingMaskIntoConstraints property to false.

Resources