简体   繁体   中英

macOS - Swift 4.0 Container View does not show NSView

I'm writing my first macOS App with Swift 4.0 and currently I'm struggling with my Container View.

I've this layout

Layout while running the app

The issue is, when I click on one of the TableView Items my Container View does not load the NSView with the "THEMA 1" label in it. (All TableView Items should load the "THEMA 1" View)

Here is my ViewController code

import Cocoa

class ViewController: NSViewController {

    //VARS
    var tableViewArray = ["Thema 1", "Thema 2", "Thema 3", "Thema 4", "Thema 5"]
    var containerViewArray: [NSView]!
    var thema1View = Thema1()

    //IBOutlets
    @IBOutlet weak var tableView: NSTableView!
    @IBOutlet weak var container: NSView!

    override func viewDidLoad() {
        super.viewDidLoad()

        //setup TableView
        tableView.delegate = self
        tableView.dataSource = self
        tableView.action = #selector(onItemClicked)
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }

}

//Extensions
extension ViewController: NSTableViewDelegate, NSTableViewDataSource {

    //show what is clicked on tableView
    @objc private func onItemClicked() {
        if (tableView.clickedRow <= tableViewArray.count - 1) && (tableView.clickedRow >= 0)  {
            print("\(tableViewArray[tableView.clickedRow]), clicked")
            removeAllSubView()
            container.addSubview(thema1View, positioned: .above, relativeTo: container)
        }
        else {
            print("There is no content in this cell")
        }

    }

    //removes all SubViews from containerView
    func removeAllSubView() {
        for view in container.subviews{
            view.removeFromSuperview()
        }
    }

    //rows in tableViewArray
    func numberOfRows(in tableView: NSTableView) -> Int {
        return tableViewArray.count
    }

    //populate the tableView
    func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
        return tableViewArray[row]
    }

}

Thema1 ViewController code

import Cocoa

class Thema1: NSView {

    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)

        // Drawing code here.
    }

}

I think the issue is buried in the onItemClicked() method, but as I mentioned I'm quite new to macOS and Swift 4.0. Therefore I've found quite many results regarding iOS but a few macOS, but nothing hinting to my case.

Thank you for taking your time and best regards, Danny

I found sample code SourceView but it is rather complicated and in Objective-C. Here's my translation of the relevant part to Swift (I'm not very familiar with Swift).

class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {

    var tableViewArray = ["Thema 1", "Thema 2", "Thema 3", "Thema 4", "Thema 5"]
    var detailViewController: NSViewController?

    @IBOutlet weak var container: NSView!

    @IBAction func tableViewClickAction(_ tableView: NSTableView) {
        if tableView.clickedRow >= 0  {
            print("\(tableViewArray[tableView.clickedRow]), clicked")

            // remove the detail view if there is one
            if let oldViewController = detailViewController {
                oldViewController.view.removeFromSuperview()
                oldViewController.removeFromParentViewController()
                detailViewController = nil
            }

            // determine the identifier of the new detail view, this is the Storyboard ID of the detail scene
            var sceneIdentifier: NSStoryboard.SceneIdentifier?
            switch tableView.clickedRow {
                case 0:
                    sceneIdentifier = NSStoryboard.SceneIdentifier(rawValue: "Thema1")
                case 1:
                    sceneIdentifier = NSStoryboard.SceneIdentifier(rawValue: "Thema2")
                case 2:
                    sceneIdentifier = NSStoryboard.SceneIdentifier(rawValue: "Thema3")
                case 3:
                    sceneIdentifier = NSStoryboard.SceneIdentifier(rawValue: "Thema4")
                case 4:
                    sceneIdentifier = NSStoryboard.SceneIdentifier(rawValue: "Thema5")
                default:
                    sceneIdentifier = nil
            }

            if sceneIdentifier != nil {
                // load the new detail controller and view from the storyboard
                detailViewController = self.storyboard?.instantiateController(withIdentifier:sceneIdentifier!) as? NSViewController
                if let newViewController = detailViewController {
                    newViewController.view.translatesAutoresizingMaskIntoConstraints = false
                    // add controller and view
                    self.addChildViewController(newViewController)
                    container.addSubview(newViewController.view)
                    // add constraints
                    let views = ["targetView": newViewController.view]
                    let horizontalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|[targetView]|",
                                                    options: [], metrics: nil, views: views)
                    let verticalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:|[targetView]|",
                                                    options: [], metrics: nil, views: views)
                    NSLayoutConstraint.activate(horizontalConstraints)
                    NSLayoutConstraint.activate(verticalConstraints)
                }
            }
        }
        else {
            print("Clicked outside the cells")
        }
    }

}

Thank your for helping me out with the storyboard idea. I've made a test dummy, where I had my Main view and made two ViewControllers with labels in it. All ViewControllers got their Storyboard-IDs. The Main view had two buttons, both assigned to one of the ViewControllers. By clicking them, you will load one of the Test ViewControllers. I came up with this

import Cocoa

class ViewController: NSViewController {

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

override var representedObject: Any? {
    didSet {
    // Update the view, if already loaded.
    }
}

func switchViews(viewNumber: Int) {
    let storyboard = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil)
    var controller = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "Main"))

    switch viewNumber {
        case 1:
            print("View: 1")
            controller = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "Test1"))
        case 2:
            print("View: 2")
            controller = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "Test2"))
        default:
            print("Default");
    }

    if let window = NSApplication.shared.mainWindow {
        window.contentViewController = controller as? NSViewController
    }
}

@IBAction func buttonAction(_ sender: NSButton) {
    var viewNumber: Int = 0

    switch sender.title {
        case "controller1":
            viewNumber = 1
            print("Button: 1")
        case "controller2":
            viewNumber = 2
            print("Button2: 2")
        default:
            print("Default")
    }

    switchViews(viewNumber: viewNumber)
}

}

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