简体   繁体   中英

NSTextView with NSTextTable: Set minimum width with horizontal scrolling?

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:

  1. Have the table expand across the full width of the text view, each column being of the same width
  2. Have a minimum width for the table/textView to prevent the table from being squished together when the user resizes the window and makes it very small; show a horizontal scroll bar instead.

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.

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.

Screen recording

Sorry for the GIF quality, but the limit is 2MB.

在此处输入图像描述

Sample project

  • Did add Text View in IB and connected it to the outlet
  • Rest is done in the code

Important parts

Scrollers

Set them both and let them autohide based on the content.

scrollView.hasVerticalScroller = true
scrollView.hasHorizontalScroller = true
scrollView.autohidesScrollers = true

Toggle text view resizing & set container size

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

Full code

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM