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

r9f1avp5  于 2022-12-10  发布在  Swift
关注(0)|答案(3)|浏览(176)

Gif to understand easier
是否有任何方法可以禁用SidebarListStyle NavigationViews的可折叠性?

k5ifujac

k5ifujac1#

编辑:这个方法在2022年底仍然有效,并且从未停止在任何版本的macOS上工作(最新的Ventura 13.1)。不知道为什么这里有答案暗示不一样。如果Introspection库改变了他们的API,你可能需要相应地更新你的调用,但解决方案的要点是相同的。
使用此SwiftUI内检库: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()
}
7cjasjjr

7cjasjjr2#

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
}
rm5edbpk

rm5edbpk3#

虽然Oskar在Introspect库中使用的方法不再起作用,但我确实找到了另一种方法,可以使用Introspect防止侧栏折叠。

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")
                
}

话虽如此,我们不知道这种方法能用多久。苹果可能会改变NavigationView的工作方式,这种方法可能会在未来停止工作。

相关问题