在macOS中,使用SwiftUI设置侧边栏视图的宽度

12

我正在使用NavigationView在Mac应用程序的窗口中显示SidebarView和DetailView:

import SwiftUI

private let fruits = [" Apple", " Coconut", " Mango", " Kiwi"]

struct SidebarView: View {

    @Binding var selectedFruit: String?

    var body: some View {
        List(fruits, id: \.self, selection: $selectedFruit) { fruit in
            Text("\(fruit)")
        }
        .listStyle(SidebarListStyle())
        .frame(minWidth: 180, idealWidth: 200, maxWidth: 300)
    }
}

struct DetailView: View {

    @Binding var fruit: String?

    var body: some View {
        Text("\(fruit ?? "Default Fruit")")
            .font(.headline)
            .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

struct ContentView: View {

    @State private var selectedFruit: String?

    var body: some View {
        NavigationView {
            SidebarView(selectedFruit: $selectedFruit)
            DetailView(fruit: $selectedFruit)
        }
        .frame(width: 500, height: 400)
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

通过在窗口中拖动中央分隔条,可以调整SidebarView的宽度。我希望侧边栏有一个初始宽度为200,最小宽度为180,最大宽度为300。我尝试通过设置List的框架来实现这一点,确实设置了最大宽度,但仍然可以完全折叠侧边栏。此外,侧边栏的初始宽度似乎是由minWidth而不是idealWidth定义的。


你排好序了吗?我发现在运行/构建之间存在一些自动SceneStorage,因此很难确定每个更改对于新用户会产生什么影响。与你不同,我无法为侧边栏设置maxWidth,而是只能强制侧边栏内容在侧边栏扩展时居中。我必须将.maxWidth设置为无穷大。同样,minWidth仅在隐藏侧边栏之前设置“压缩点”。使用.layoutPriority(1)或.fixedSize(...)都没有帮助。这一切都相当出乎意料。即使SidebarCommands()命令也不像预期的那样出现。 - Beginner
@初学者 我认为下一个版本的SwiftUI已经解决了这个问题。但在确认修复之前,我还在等待它退出测试版。 - wigging
很遗憾,我正在使用Beta版... - Beginner
有人找到解决方案了吗?我也无法为我的侧边栏设置最大宽度。 - Joey Slomowitz
你这里的代码应该是可以工作的。SidebarView 不应该超过 300 的大小。但是很遗憾它失败了。我也有类似的问题(在 macOS 上),尝试找出原因或解决方法都失败了 :-( - Klajd Deda
3个回答

10

对于任何想要知道如何在macOS中设置侧边栏最大宽度的人,实际上是不需要设置的。如果这样做,视图将停止增长,然后被困在侧边栏的中间,而侧边栏将继续扩展。

我花了一分钟的时间才想出来,你需要做的是设置另一个视图——详细视图的最小宽度。然后,侧边栏会增长直到无法再增长为止。你会注意到甚至Finder的侧边栏也会不断增长,直到达到所谓的详情最小宽度。


1
你能提供一些关于这个答案的示例代码吗? - wigging
1
实际上,这是正确的答案。 - mayqiyue
哦,这很有趣...但对我来说毫无意义。我不想限制细节。细节应该占用所有可用的宽度-侧边栏宽度。我想限制侧边栏不要变得过大。 - Klajd Deda

0

受到MScottWaller的答案启发,我为详细视图的最小尺寸添加了一些计算。这似乎将侧边栏固定在220到380之间。在macOS 126.1 / Xcode 14.0.1上运行。

关键部分是private func minDetailWidth()

    struct ItemListView: View {
        struct ItemRow: View {
            struct ItemView: View {
                let item: Item

                var body: some View {
                    VStack {
                        Image(systemName: item.imageName)
                            .clipShape(Circle())
                            .overlay(Circle().stroke(Color.white, lineWidth: 2))
                            .padding(2)
                            .overlay(Circle().strokeBorder(Color.black.opacity(0.1)))
                            .shadow(radius: 3)
                            .padding(4)

                        Text(item.name)
                            .font(.largeTitle)
                    }
                }
            }

            let item: Item

            var body: some View {
                NavigationLink(destination: ItemView(item: item)) {
                    HStack {
                        Image(systemName: item.imageName)
                            .resizable()
                            .frame(width: 50, height: 50)
                            .clipShape(Circle())
                            .overlay(Circle().stroke(Color.white, lineWidth: 2))
                            .padding(2)
                            .overlay(Circle().strokeBorder(Color.black.opacity(0.1)))
                            .shadow(radius: 3)
                            .padding(4)

                        Text(item.name)
                            .font(.largeTitle)
                    }
                }
            }
        }

        let items: [Item]

        var body: some View {
            List(items) { fruit in
                ItemRow(item: fruit)
            }
        }
    }

    struct Item: Identifiable {
        let id = UUID()
        let name: String
        let imageName: String
        let color: Color
    }

    class Model: ObservableObject {
        @Published var transportation: [Item] = loadTransportation()
        @Published var vegetables: [Item] = loadVegetables()

        static func loadTransportation() -> [Item] {
            return [
                Item(name: "Airplane", imageName: "airplane", color: .orange),
                Item(name: "Car", imageName: "car", color: .blue),
                Item(name: "Bus", imageName: "bus.fill", color: .red),
                Item(name: "Tram", imageName: "tram.fill", color: .pink),
                Item(name: "Ferry", imageName: "ferry", color: .purple),
                Item(name: "Bicycle", imageName: "bicycle", color: .green),
            ]
        }

        static func loadVegetables() -> [Item] {
            return [
                Item(name: "Spinach", imageName: "spinach", color: .red),
                Item(name: "Lettuce", imageName: "lettuce", color: .orange),
                Item(name: "Tomatoes", imageName: "tomatoes", color: .green),
                Item(name: "Onion", imageName: "onion", color: .blue),
            ]
        }
    }

    @ObservedObject private var model = Model()
    private var sideBarMaxWidth = 380.0

    /**
     window width minus the sideBarMaxWidth
     */
    private func minDetailWidth(_ proxy: GeometryProxy) -> Double {
        let rv_ = proxy.size.width - sideBarMaxWidth
        let rv = max(rv_, 480)
        // Log4swift[Self.self].info("\(rv)")
        return rv
    }

    var body: some View {
        GeometryReader { proxy in
            NavigationView {
                List {
                    NavigationLink(
                        "Fruits",
                        destination:
                            ItemListView(items: self.model.transportation)
                            .frame(minWidth: minDetailWidth(proxy), idealWidth: 840, maxWidth: .infinity)
                    )

                    NavigationLink(
                        "Vegetables",
                        destination:
                            ItemListView(items: self.model.vegetables)
                            .frame(minWidth: minDetailWidth(proxy), idealWidth: 840, maxWidth: .infinity)
                    )
                }
                .frame(minWidth: 220, maxWidth: sideBarMaxWidth)

                Text("Nothing Selected")
                    .frame(minWidth: minDetailWidth(proxy), maxWidth: .infinity)
            }
        }
    }
}

struct ExampleView_Previews: PreviewProvider {
    static var previews: some View {
        ExampleView()
        // .background(Color(NSColor.windowBackgroundColor))
            .environment(\.colorScheme, .light)

        ExampleView()
        // .background(Color(NSColor.windowBackgroundColor))
            .environment(\.colorScheme, .dark)
    }
}

-2
也许你可以为DetailView设置minWidth。我尝试过,效果很好。

3
请分享代码作为您回答的一部分。 - wigging
3
请提供一个简短的代码示例。 - Sworup Shakya
2
目前你的回答不太清晰。请[编辑]以添加更多细节,以帮助他人理解这如何回答所问的问题。您可以在帮助中心找到有关编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接