NSScrollView only scrolls vertically for NSTableView after window resize

Hi everyone,

I’m looking for help with an issue where using insertRows to add a row to an NSTableView requires resizing the window before I can scroll to the newly added rows that extend beyond the visible area of the NSScrollView.

import Cocoa

class ViewController: NSViewController {
    
    var data = Constants.movies
    
    
    // Table components
    var titleField = NSTextField()
    var directorField = NSTextField()
    var releaseYearField = NSTextField()
    var addMovieButton = NSButton(title: "Add Movie", image: NSImage(systemSymbolName: "plus", accessibilityDescription: "")!, target: nil, action: #selector(addMovie))
    
    var table = NSTableView()
    var titleColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.titleColumnId))
    var directorColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.directorColumnId))
    var releaseYearColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.releaseColumnId))
    
    // Scroll view
    let scrollView = NSScrollView()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        view.wantsLayer = true
        view.layer?.backgroundColor = NSColor.black.cgColor
        
        configure()
    }
    
    private func configure() {
        titleField.translatesAutoresizingMaskIntoConstraints = false
        directorField.translatesAutoresizingMaskIntoConstraints = false
        releaseYearField.translatesAutoresizingMaskIntoConstraints = false
        addMovieButton.translatesAutoresizingMaskIntoConstraints = false
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        table.translatesAutoresizingMaskIntoConstraints = false
        
        titleField.placeholderString = "Movie Title"
        directorField.placeholderString = "Name of Director"
        releaseYearField.placeholderString = "Year Released"
        
        // Configure table
        table.addTableColumn(titleColumn)
        table.addTableColumn(directorColumn)
        table.addTableColumn(releaseYearColumn)
        
        titleColumn.title = "Movie Title"
        directorColumn.title = "Director"
        releaseYearColumn.title = "Year Released"
        
        table.delegate = self
        table.dataSource = self
        
        table.focusRingType = .none
        
        // Configure scroll view
        scrollView.documentView = table
        scrollView.hasVerticalScroller = true
        scrollView.hasHorizontalScroller = false
        scrollView.autohidesScrollers = true
        
        
        // Add views to the hierarchy
        view.addSubview(titleField)
        view.addSubview(directorField)
        view.addSubview(releaseYearField)
        view.addSubview(addMovieButton)
        view.addSubview(scrollView)
//        view.addSubview(table)
        
        NSLayoutConstraint.activate([
            titleField.widthAnchor.constraint(equalToConstant: 150),
            directorField.widthAnchor.constraint(equalToConstant: 150),
            releaseYearField.widthAnchor.constraint(equalToConstant: 150),
            addMovieButton.widthAnchor.constraint(equalToConstant: 100),
            
            titleField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),
            directorField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),
            releaseYearField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),
            addMovieButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),
            
            directorField.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant: -10),
            releaseYearField.leadingAnchor.constraint(equalTo: view.centerXAnchor, constant: 10),
            
            titleField.trailingAnchor.constraint(equalTo: directorField.leadingAnchor, constant: -20),
            addMovieButton.leadingAnchor.constraint(equalTo: releaseYearField.trailingAnchor, constant: 20),
            
            
            scrollView.topAnchor.constraint(equalTo: titleField.bottomAnchor, constant: 20),
            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20),
            
//            table.widthAnchor.constraint(equalTo: scrollView.contentView.widthAnchor),
//            table.heightAnchor.constraint(equalTo: scrollView.contentView.heightAnchor)
            
        ])
        
    }
    
    @objc private func addMovie() {
        let title = titleField.stringValue
        let director = directorField.stringValue
        
        guard let year = Int(releaseYearField.stringValue) else {
            return
        }
        
        let movie = Movie(title: title, director: director, releaseYear: year)
        
        data.append(movie)

        // Approach 1
        // table.reloadData()
        
        // Approach 2
        let newRow = data.count - 1
        
        table.insertRows(at: IndexSet(integer: newRow), withAnimation: .slideDown)
        
        
    }

Using table.reloadData works fine and I can scroll to the new rows as I add them, but it doesn't have the smooth animation I want to achieve.

What is the best practice and correct way for using table.insertRows to avoid this issue?

Note: I am using programmatic constraints only.

Answered by alejoaa in 862639022

I was able to solve the issue by removing table.translatesAutoresizingMaskIntoConstraints = false. It seems this should not be set to false even when using Auto Layout for an NSTableView inside of an NSScrollView.

Accepted Answer

I was able to solve the issue by removing table.translatesAutoresizingMaskIntoConstraints = false. It seems this should not be set to false even when using Auto Layout for an NSTableView inside of an NSScrollView.

NSScrollView only scrolls vertically for NSTableView after window resize
 
 
Q