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

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

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!

ibaction not trigger in NSPersistentDocument for macOS

I have an application macOS with 2 buttons but they are not trigger
I have connected up IBActions to buttons
Document
override func windowControllerDidLoadNib(_ windowController: NSWindowController) {
super.windowControllerDidLoadNib(windowController)
// user interface preparation code
guard let context = self.managedObjectContext else { fatalError("context is nil") }
mainObjectContext = context
let mainWindowController = MainWindowController(nibName: NSNib.Name(rawValue: "MainWindowController"), bundle: nil)
customView1.addSubview(mainWindowController.view)
setUpLayoutConstraints(item: mainWindowController.view, toItem: customView1)
}
func setUpLayoutConstraints(item : NSView, toItem: NSView)
{
item.translatesAutoresizingMaskIntoConstraints = false
let sourceListLayoutConstraints = [
NSLayoutConstraint(item: item, attribute: .left, relatedBy: .equal, toItem: toItem, attribute: .left, multiplier: 1, constant: 0),
NSLayoutConstraint(item: item, attribute: .right, relatedBy: .equal, toItem: toItem, attribute: .right, multiplier: 1, constant: 0),
NSLayoutConstraint(item: item, attribute: .top, relatedBy: .equal, toItem: toItem, attribute: .top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: item, attribute: .bottom, relatedBy: .equal, toItem: toItem, attribute: .bottom, multiplier: 1, constant: 0)]
NSLayoutConstraint.activate(sourceListLayoutConstraints)
}
and MainWindowController
class MainWindowController: NSViewController {
#objc var managedObjectContext: NSManagedObjectContext = mainObjectContext
#objc dynamic var customSortDescriptors = [NSSortDescriptor(key: "name", ascending: true, selector: #selector(NSString.localizedStandardCompare(_:)))];
#IBOutlet weak var textFiled: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
print("hello")
textFiled.stringValue = "hello"
}
#IBAction func actionAddNew(_ sender: Any) {
print("add")
textFiled.stringValue = "add"
}
#IBAction func actionRemove(_ sender: Any) {
print("remove")
textFiled.stringValue = "remove"
}
}
I have all tried I do not know what to do
I have certainly forgotten something
in another application NSPersistentDocument there is no problem
https://www.dropbox.com/s/qlww3hgii7wamup/CoreDataDragDropSwift2.zip?dl=0
enter image description here

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.

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.

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

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.

Resources