NSWindow launching with wrong size after setting contentViewController to NSTabViewController
Asked Answered
H

3

6

I have an Xcode project with an NSWindowController whose contentViewController was set to a subclass of NSViewController. I recently removed the NSViewController subclass from the storyboard and replaced the contentViewController with an NSTabViewController subclass.

Now, when I run the application, the NSWindow opens with a size of 500x500 instead of the size of the first tab. What's more, there is no view I can see in the storyboard that has a size of 500x500, and that size isn't being programmatically, either. The window itself is set to a different size, as is the view in the NSTabViewController's first NSViewController.

I'm assuming that there is some sort of constraint I have to set somewhere, but if there is, I don't know where/how to find it. Using Xcode 9.2 and High Sierra.

Programmatically setting the window's size to the correct size in windowDidLoad() works, but if I ever change the size of the view, I'll have to change that, as well, which will get old, quick.

Sorry if this is vague; I genuinely have no clue what kind of screenshot or code snippet would be helpful.

Hemisphere answered 30/1, 2018 at 7:37 Comment(3)
Problem still present in Xcode 11.4Astronomer
@RaffaeleCandeliere did you add subviews and constraints to the view?Endue
@Endue What do you exactly mean by "view"? I do have subviews (with constraints and so forth) in each single tab of my tabview, but I'm not sure if you're talking about them. However, I've bypassed the issue with this solution (gist.github.com/mminer/caec00d2165362ff65e9f1f728cecae2). It's not a fix but it works for my needs.Astronomer
T
9

I recently ran into this frustrating problem as well.

There are a couple options to workaround this problem:

  1. As you mentioned, set preferredContentSize in each of your custom view controllers that hold the tab's content to your desired size. This is inflexible but it does work.

    // Swift
    class FooViewController: ViewController {
    
        override func viewWillAppear() {
            super.viewWillAppear()
    
            preferredContentSize = NSSize(width: 400, height: 280)
        }
    }
    
  2. I found a hint to a better solution in this SO answer. You can add a subview (stackview, nsview, etc...) to the main view of the view controller that handles the tab's content (phew!) and then add constraints that pin it to each edge and add constraints that set the size.

Here's a screenshot of what it looks like in Interface Builder. I added a Stack View and then added 6 constraints.

Hope this helps.

Tanaka answered 5/4, 2018 at 12:9 Comment(0)
A
4

Joshua's answer with setting the preferredContentSize did the trick, all kudos to him! One remark worth making is that since this is done exclusively for the parent tab view controller it's a good idea to subclass it and move this handling into tabView(_ tabView: NSTabView, didSelect tabViewItem: NSTabViewItem?) delegate method, which gets invoked when the tab is selected:

override func tabView(_ tabView: NSTabView, didSelect tabViewItem: NSTabViewItem?) {
    tabViewItem?.viewController?.preferredContentSize = tabViewItem?.view?.frame.size
    // Alternatively: tabViewItem?.viewController?.preferredContentSize = tabViewItem?.view?.fittingSize
    super.tabView(tabView, didSelect: tabViewItem)
}

This way the preferred content size is always up to date and you can worry not about manually refreshing it, assuming the view provides the correct frame size or fitting size, which is easily achieved with constraints.

This method also get's invoked after the window controller finishes loading and where the 500×500 gets initially set.

Setting the preferred content size in every tabbed view controller itself is not ideal: the same code is duplicated across multiple controllers and adds unnecessary noise if these controllers are reused else where.

Aglaia answered 26/1, 2019 at 14:19 Comment(0)
G
1

I had a similar issue. I added a view controller with a container view as the window content and pointed the container view content to the tab view controller.

Galenism answered 3/5, 2018 at 13:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.