How to make a resizable HSplitView for macOS?

Hello, I'm trying to mock up a simple UI for a typical Mac app with a sidebar and a content area.

Starting from the SwiftUI Xcode template, I got this far:


struct ContentView : View {
    var body: some View {
        HSplitView() {
            List() {
                Text("Sidebar")
                Text("Sidebar")
                Text("Sidebar")
                Text("Sidebar")
            }
            List() {
                Text("Content")
                Text("Content")
                Text("Content")
                Text("Content")
            }
        }
        .frame(minWidth: 100, maxWidth: .infinity, minHeight: 100, maxHeight: .infinity, alignment: .topLeading)
    }
}


Two big issues so far:


1. The top-level HSplitView does not resize with the window. It remains at the size it is created when the app launches, regardless of how you resize the window. Does the NSHostingView need to have an autoresizing mask or layout constraints? (It doesn't come with any in the Xcode template.)


2. I can't seem to make the two subviews of the splitView resizable by the splitter, even if I give them frame() modifiers.


Since this API is so new, I can't find any examples online.

Has anyone successfully made a macOS app in SwiftUI that has typical sidebar/content splitView that resizes with the window, and whose subviews can be resized by dragging the spliiter?

Thanks!

Any luck? I'm running into the same issues.

Nope. Spent a whole day trying to use VSplitView and HSplitView. They must be bugged atm.

With the new beta 2, the divider is resizable for me by default.


I am trying to simulate an NSOutlineView by using a sidebar with nested sublists:


struct ContentView : View {
    var body: some View {
        HSplitView() {
            List() {
                
                Section(header: Text("Section 1")) {
                    Text("Sub 1.1")
                    Text("Sub 1.2")
                }
                
                Section(header: Text("Section 2")) {
                    Text("Sub 2.1")
                    List {
                        Section(header: Text("Subsection 2.2")) {
                            Text("Sub 2.2.1")
                            Text("Sub 2.2.2")
                        }
                        Section(header: Text("Subsection 2.3")) {
                            Text("Sub 2.3.1")
                            Text("Sub 2.3.2")
                        }
                    } //.frame(height: 140)
                }
                
                Section(header: Text("Section 3")) {
                    Text("Sub 3.1")
                    Text("Sub 3.2")
                }
                
                }.listStyle(.sidebar)
            
            List() {
                Text("Content")
                Text("Content")
                Text("Content")
                Text("Content")
            }
        }
    }
}


By uncommenting the 22nd line, you can see and un/fold the sections of the second sublist, otherwise SwiftUI assigns a fixed height to all the sections. I can't find a simple way to force the height of a section to the intrinsic height of its content.

Assuming that you want to use the Master-Details pattern, I think that Approach should be to use Navigation Controls and not use the List (as list will require using binding and glue-code to display Details: this is a lot of work for a basic UI pattern, way too complex).


The Master-details pattern, on WWDC slides uses Navigation controls:

https://developer.apple.com/videos/play/wwdc2019/216/ at 55:10 and slide 278 onwards.


The issue appers to be that Mac implemention of SwitUI is pretty buggy and thus Navigation is not available. I am pretty sure that Developers at Apple are getting beaten eveyday to fix SwiftUI (fill the the gap between over-promised and under-delivered features).

I am skeptical that it Mac SwitUI will be even ready for September Release.

Does this implementation work as of beta 2? I just get a huge list, no master-detail.

Without navigation, the closest one can do is generate new views for every click



import SwiftUI

struct ContentView : View {
  
    @State var clickedContent: RandomListStruct?
    @State var clickedUseCase: Int?

    var var_list : [RandomListStruct]
    let zero = "use a default view as in WWDC video"

    var body: some View {
        HStack (alignment: .top) {

          
            VStack (alignment: .leading){

                List (selection: $clickedContent) {
                    Text ("Master Record").color(.orange)
                    Divider()

                    ForEach(var_list.identified(by: \.self)) { rls in
                        HStack {
                            Text("\(rls.name)")
                            Spacer()
                            Text("\(rls.address)")
                          
                        }
                    }
                }
            }.frame(maxWidth: 250, maxHeight: .infinity)
          
          
            VStack {
                List {
                    Text ("Details ").color(.orange)
                    Divider()
                    if (clickedContent?.name ?? zero) == zero {
                        Text("Please select a Row").color(.red)
                      
                    } else {
                        VStack(alignment: .leading) {
                          
                            Text("Name : \(clickedContent!.name)").color(.green)
                            Text("Address : \(clickedContent!.address)").color(.green)
                          
                        }
                      
                    }
                }
            }.frame(maxWidth: 500, maxHeight: .infinity)
          
        }
    }
}

struct RandomListStruct: Hashable, Codable, Identifiable {
    var id : Int
    var name : String
    var address : String
}

let var_list1 = [
    RandomListStruct(id: 1, name: "John", address: "200 Hollywood"),
    RandomListStruct(id: 2, name: "Jane", address: "212 Willowdale"),
    RandomListStruct(id: 3, name: "Ishan", address: "801 Elmwood"),
    RandomListStruct(id: 4, name: "Kris", address: "214 Front"),
    RandomListStruct(id: 5, name: "Ishani", address: "215 Bay St")
]

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
      
        ContentView(var_list: var_list1)
    }
}
#endif

I think I figured it out. Wrapping your main ContentView in GeometryReader and setting frame modifier to explicit gemoetry of the view worked for me:


struct ContentView: View {
     var body: some View {
        GeometryReader { geometry in
            VStack {
                HSplitView {
                    VStack { Text("Pane 1") }.frame(maxWidth: .infinity, maxHeight: .infinity)
                    VStack { Text("Pane 2") }.frame(maxWidth: .infinity, maxHeight: .infinity)
                }
            }.frame(width: geometry.size.width, height: geometry.size.height)
        }
     }
}
How to make a resizable HSplitView for macOS?
 
 
Q