Due to limitations with DisclosureGroup
functionality with a List
, I'm looking into using NSOutlineView
wrapped with NSViewRepresentable
.
However, with this simple example, when I create the view I'm not seeing all of the required NSOutlineViewDataSource
functions being called on the Coordinator that I assume should populate the view. Only outlineView(_:numberOfChildrenOfItem:)
is called, then updateNSView(_:context:)
is called after that.
I added a border to check the wrapped view is actually being drawn in the ContentView
and it seems to be.
What am I missing?
Wrapping the NSOutlineView:
import SwiftUI
struct AppKitOutlineView: NSViewRepresentable {
//ViewRepresentable Stuff
class Coorindinator: NSObject, NSOutlineViewDataSource{
var theData = ["One", "Two", "Three", "Four"]
//NSOutlineViewDataSource Stuff
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
print(#function)
return theData[index]
}
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
print(#function)
return false
}
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
print(#function)
print (theData.count)
return theData.count
}
func outlineView(_ outlineView: NSOutlineView, objectValueFor tableColumn: NSTableColumn?, byItem item: Any?) -> Any? {
print(#function)
return item
}
}
func makeCoordinator() -> Coorindinator {
print(#function)
return Coorindinator()
}
func makeNSView(context: Context) -> some NSView {
print(#function)
let outlineView = NSOutlineView()
outlineView.dataSource = context.coordinator
return outlineView
}
func updateNSView(_ nsView: NSViewType, context: Context) {
print(#function)
//Nothing yet
}
}
ContentView:
import SwiftUI
struct ContentView: View {
var body: some View {
VStack{
Text("Thing")
AppKitOutlineView().border(Color.red)
}
}
}
This is what I can see is happening in the console:
makeCoordinator()
makeNSView(context:)
outlineView(_:numberOfChildrenOfItem:)
4
updateNSView(_:context:)
The others DataSource depend on outline view appearance, which return nil in your example. So that's why it's not get called. Try to conform dataCellFor tableColumn
in NSOutlineViewDelegate
:
func makeNSView(context: Context) -> some NSView {
...
outlineView.delegate = context.coordinator
}
class Coorindinator: NSObject, NSOutlineViewDataSource, NSOutlineViewDelegate {
func outlineView(_ outlineView: NSOutlineView, dataCellFor tableColumn: NSTableColumn?, item: Any) -> NSCell? {
if let item = item as? String {
let cell = NSCell(textCell: item)
return cell
} else {
return NSCell()
}
}
...
}
Then the output should be:
makeCoordinator()
makeNSView(context:)
outlineView(_:numberOfChildrenOfItem:)
4
outlineView(_:child:ofItem:)
outlineView(_:isItemExpandable:)
outlineView(_:child:ofItem:)
outlineView(_:isItemExpandable:)
outlineView(_:child:ofItem:)
outlineView(_:isItemExpandable:)
outlineView(_:child:ofItem:)
outlineView(_:isItemExpandable:)
updateNSView(_:context:)
updateNSView(_:context:)
makeCoordinator()
makeNSView(context:)
outlineView(_:numberOfChildrenOfItem:)
...