SwiftUI - 如何禁用侧边栏折叠?

问题描述 投票:0回答:3

Gif更容易理解

有什么方法可以禁用 SidebarListStyle NavigationViews 的可折叠性吗?

swift macos swiftui
3个回答
4
投票

编辑:此方法截至 2022 年末仍然有效,并且从未停止在任何版本的 macOS 上工作(直到最新的 Ventura 13.1)。不知道为什么这里有答案提出其他建议。如果 Introspection 库更改了其 API,您可能需要相应地更新您的调用,但解决方案的要点是相同的。


使用这个 SwiftUI Introspection 库: https://github.com/siteline/SwiftUI-Introspect

我们可以通过扩展它们的功能来反思底层

NSSplitView

public func introspectSplitView(customize: @escaping (NSSplitView) -> ()) -> some View {
    return introspect(selector: TargetViewSelector.ancestorOrSibling, customize: customize)
}

然后在

View
上创建通用扩展:

public extension View {
    func preventSidebarCollapse() -> some View {
        return introspectSplitView { splitView in
            (splitView.delegate as? NSSplitViewController)?.splitViewItems.first?.canCollapse = false
        }
    }
}

可以在我们的侧边栏上使用:

var body: some View {
    (...)
    MySidebar()
        .preventSidebarCollapse()
}

3
投票

Oskar 提到的内省库不适用于 MacOS。

受此启发,我找到了适用于 MacOS 的解决方案。

解决方案背后的合理性是使用一种微妙的方式来找出

NavigationView
的父视图,即当前窗口中的
NSSplitViewController

以下代码在 XCode 13.2 和 macOS 12.1 上进行了测试。

var body: some View {
    Text("Replace with your sidebar view")
       .onAppear {
           guard let nsSplitView = findNSSplitVIew(view: NSApp.windows.first?.contentView), let controller = nsSplitView.delegate as? NSSplitViewController else {
               return
           }
           controller.splitViewItems.first?.canCollapse = false
                // set the width of your side bar here.
           controller.splitViewItems.first?.minimumThickness = 150
           controller.splitViewItems.first?.maximumThickness = 150
       }
}

private func findNSSplitVIew(view: NSView?) -> NSSplitView? {
    var queue = [NSView]()
    if let root = view {
        queue.append(root)
    }
    while !queue.isEmpty {
        let current = queue.removeFirst()
        if current is NSSplitView {
            return current as? NSSplitView
        }
        for subview in current.subviews {
            queue.append(subview)
        }
    }
    return nil
}


0
投票

虽然 Oskar 在 Introspect 库中使用的方法不再有效,但我确实找到了另一种使用 Introspect 防止侧边栏折叠的方法。首先,你需要对View进行扩展:

extension View {
    public func introspectSplitView(customize: @escaping (NSSplitView) -> ()) -> some View {
        return inject(AppKitIntrospectionView(
            selector: { introspectionView in
                guard let viewHost = Introspect.findViewHost(from: introspectionView) else {
                    return nil
                }
                return Introspect.findAncestorOrAncestorChild(ofType: NSSplitView.self, from: viewHost)
            },
            customize: customize
        ))
    }
}

然后执行以下操作:

NavigationView {
     SidebarView()
         .introspectSplitView { controller in
                    (controller.delegate as? NSSplitViewController)?.splitViewItems.first?.canCollapse = false
                    
         }
            
     Text("Main View")
                
}

话虽如此,我们不知道这实际上能持续多久。 Apple 可能会更改 NavigationView 的工作方式,并且此方法将来可能会停止工作。

© www.soinside.com 2019 - 2024. All rights reserved.