Reputation: 6957
I have a Cocoa app with a NSTextView
. I display a rather large table (made via NSAttributedString
, NSTextTable
, and NSTextTableBlock
).
I'd like to achieve the following behavior:
I managed to get either #1 working or #2, but I can't figure out how to have a minimum width of the text view while having the table stretch across the full width.
My code:
Min width, scrolling, but not expanding across full width:
self.textView.textStorage?.setAttributedString(tableString)
self.textView.textContainer?.widthTracksTextView = false
self.textView.isHorizontallyResizable = true
cellBlock.setValue(200, type: .absoluteValueType, for: .minimumWidth)
Expanding across full width, but no minimum width enforced:
self.textView.isHorizontallyResizable = true
cellBlock.setValue(relativeWidth, type: .percentageValueType, for: .width)
I also tried to set an Autolayout constraint to the text view, but that only enforced the minWidth, not showing a horizontal scrollbar.
Upvotes: 1
Views: 529
Reputation: 21229
What about other content? Like text above/below the table? Shrink? Maintain same minimum width as the table? My assumption is same width as the table.
The following example is not a full answer, treat it as proof-of-concept you have to start with.
Sorry for the GIF quality, but the limit is 2MB.
Set them both and let them autohide based on the content.
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalScroller = true
scrollView.autohidesScrollers = true
This is a lame implementation because of the viewDidLayout
override, etc. For example - if you're fast enough with your mouse & window resizing, you can end up with a size much smaller than 300, etc.
The important part here is what properties do I change and that I stick to a fixed containerSize
(horizontal) when a threshold is reached.
if textView.bounds.size.width > 300 {
textView.isHorizontallyResizable = false
textView.textContainer?.widthTracksTextView = true
} else {
textView.textContainer?.widthTracksTextView = false
textView.isHorizontallyResizable = true
textView.textContainer?.containerSize = NSSize(width: textView.bounds.size.width, height: CGFloat.greatestFiniteMagnitude)
}
import Cocoa
class ViewController: NSViewController {
@IBOutlet var scrollView: NSScrollView!
@IBOutlet var textView: NSTextView!
let loremIpsum = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.\n"
let loremIpsumCell = "Lorem Ipsum is simply dummy text of the printing and typesetting industry.\n"
override func viewDidLayout() {
super.viewDidLayout()
if textView.bounds.size.width > 300 {
textView.isHorizontallyResizable = false
textView.textContainer?.widthTracksTextView = true
} else {
textView.textContainer?.widthTracksTextView = false
textView.isHorizontallyResizable = true
textView.textContainer?.containerSize = NSSize(width: textView.bounds.size.width, height: CGFloat.greatestFiniteMagnitude)
}
}
override func viewDidLoad() {
super.viewDidLoad()
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalScroller = true
scrollView.autohidesScrollers = true
let content = NSMutableAttributedString(string: loremIpsum)
let table = NSTextTable()
table.numberOfColumns = 2
table.setContentWidth(100, type: .percentageValueType)
(0...1).forEach { row in
(0...5).forEach { column in
let block = NSTextTableBlock(table: table, startingRow: row, rowSpan: 1, startingColumn: column, columnSpan: 1)
block.setWidth(1.0, type: .absoluteValueType, for: .border)
block.setBorderColor(.orange)
let paragraph = NSMutableParagraphStyle()
paragraph.textBlocks = [block]
let cell = NSMutableAttributedString(string: loremIpsumCell, attributes: [.paragraphStyle: paragraph])
content.append(cell)
}
}
content.append(NSAttributedString(string: loremIpsum))
textView.textStorage?.setAttributedString(content)
}
}
Upvotes: 1