Xcode 10.1, Swift 4.2, macOS 10.14.2
I am trying to make a simple to do list app for macOS where there are a series of NSTableView
rows and inside each one is an NSTextField
. Each field is a to-do item. I want the NSTableView
rows to expand to fit the size of the text within each NSTextField
.
I have all of the following working:
NSTextField
makes the NSTableView
row expand as needed. Auto layout constraints are set in my storyboard.tableView.reloadData(forRowIndexes: ..., columnIndexes: ...)
sets the text and resizes the table row correctly.
tableView.reloadData()
always resets every NSTextField
to a single line of text as shown here:
NSTextField
after reloading the whole table, the field resizes to fit its content again:
I believe I have set all the appropriate auto layout constraints on my NSTextField
and I'm using a custom subclass for it as well (from a helpful answer here):
class FancyField: NSTextField{
override var intrinsicContentSize: NSSize {
// Guard the cell exists and wraps
guard let cell = self.cell, cell.wraps else {return super.intrinsicContentSize}
// Use intrinsic width to jibe with autolayout
let width = super.intrinsicContentSize.width
// Set the frame height to a reasonable number
self.frame.size.height = 150.0
// Calcuate height
let height = cell.cellSize(forBounds: self.frame).height
return NSMakeSize(width, height)
}
override func textDidChange(_ notification: Notification) {
super.textDidChange(notification)
super.invalidateIntrinsicContentSize()
}
}
⭐️Here is a sample project: https://d.pr/f/90CTEh
I'm at a loss as to what else I can try. Any ideas?
I think there is some basic problems with the constraints in interface builder. Resizing the window makes everything wonky. Also you should call validateEditing()
in the textDidChange(forBounds:)
in your FancyField
class.
I created a sample project, that does what you want on Github
Write a comment if you have any problems with it.
Thinking a little about it, thought i would add the meat of the code here. Only thing that really needs to work, is the update on the NSTextField when the "Tasks" is being updated. Following is the code required for the NSTextField.
public class DynamicTextField: NSTextField {
public override var intrinsicContentSize: NSSize {
if cell!.wraps {
let fictionalBounds = NSRect(x: bounds.minX, y: bounds.minY, width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
return cell!.cellSize(forBounds: fictionalBounds)
} else {
return super.intrinsicContentSize
}
}
public override func textDidChange(_ notification: Notification) {
super.textDidChange(notification)
if cell!.wraps {
validatingEditing()
invalidateIntrinsicContentSize()
}
}
}
Hope it helps.