SwiftUI 中具有不同列的侧边栏
Posted
技术标签:
【中文标题】SwiftUI 中具有不同列的侧边栏【英文标题】:Sidebar with different columns in SwiftUI 【发布时间】:2020-07-19 09:40:27 【问题描述】:我正在使用 SwiftUI 2 附带的新侧边栏以及在具有三列的大屏幕中导航的可能性。可以在此处找到有关其工作原理的示例:https://www.hackingwithswift.com/quick-start/swiftui/how-to-add-a-sidebar-for-ipados
它工作正常,但我想向前迈出一步,在我的主菜单中设置一些选项,显示三列,但其他选项只有两列。
这里是一些演示代码的示例。
import SwiftUI
struct ContentView: View
var body: some View
NavigationView
List
Section(header: Text("Three columns"))
NavigationLink(
destination: ItemsView(),
label:
Label("Animals",systemImage: "tortoise")
)
NavigationLink(
destination: ItemsView(),
label:
Label("Animals 2",systemImage: "hare")
)
Section(header: Text("Two columns"))
NavigationLink(
destination: Text("I want to see here a single view, without detail"),
label:
Label("Settings",systemImage: "gear")
)
NavigationLink(
destination: Text("I want to see here a single view, without detail"),
label:
Label("Settings 2",systemImage: "gearshape")
)
.listStyle(SidebarListStyle())
.navigationBarTitle("App Menu")
ItemsView()
DetailView(animal: "default")
struct ItemsView: View
let animals = ["Dog", "Cat", "Lion", "Squirrel"]
var body: some View
List
ForEach(animals, id: \.self) animal in
NavigationLink(
destination: DetailView(animal: animal))
Text(animal)
.listStyle(PlainListStyle())
.navigationTitle("Animals")
struct DetailView: View
var animal: String
var body: some View
VStack
Text("????")
.font(.title)
.padding()
Text(animal)
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
.previewLayout(.sizeThatFits)
如果您在 iPad Pro(12.9 英寸)中以横向模式运行代码,您可以看到树列。首先是应用程序菜单(侧边栏)。如果您单击前两个选项之一(动物和动物 2),您可以看到动物列表(第二列),当您单击某些动物时,您会到达第三列(详细视图)。 但是,当我单击菜单的最后两个选项(设置和设置 2)时,我希望只有两列。任何线索如何实现它?
如果未选择菜单中的某些第一个选项(使用 NavigationLink 中的 selected 参数),我尝试隐藏该部分,但没有运气。似乎不可能(或者我不知道)知道在侧边栏中选择了哪个选项。
欢迎提出任何想法!
【问题讨论】:
我有一个类似的问题,并通过创建两个 NavigationViews 来解决它:一个有两个条目,一个有三个。这些 NavigationView 由 if-then-else 嵌入,这取决于侧边栏的当前选择。效果很好... 感谢@Hardy,您的解决方案是一个很好的解决方法,但它不能 100% 正常工作。显示选择的选项时出现问题,在某些情况下,返回按钮无法按预期工作。我联系了 Apple 支持,但该功能不受官方支持。希望在下一个 SwiftUI 大版本中得到支持。 @jarnaez,你知道这个功能是否包含在 SwiftUI 3.0 中吗?能够根据主菜单选择在 2 或 3 列之间进行切换将是非常棒的。 嗨@Peanutsmasher,我暂时没有时间检查 SwiftUI 3 中的所有新功能和更改,但是从我所做的快速阅读中,我没有看到任何关于此功能的信息 :( 【参考方案1】:我花了几天时间才弄明白。
在不同的 iPad 设备和多任务模式下测试,一切正常。(ios14+,尚未在 iOS13 上测试)
小例子:
extension UISplitViewController
open override func viewDidLoad()
super.viewDidLoad()
self.show(.primary) // show sidebar, this is the key, toke me days to find this...
self.showsSecondaryOnlyButton = true
struct ContentView: View
@State var column: Int = 3
var body: some View
switch column
case 3: // Triple Column
NavigationView
List
HStack
Text("Triple")
.onTapGesture
column = 3
HStack
Text("Double")
.onTapGesture
column = 2
Text("Supplementary View")
Text("Detail View")
default: // Double Column
NavigationView
List
HStack
Text("Triple")
.onTapGesture
column = 3
HStack
Text("Double")
.onTapGesture
column = 2
Text("Supplementary View")
我的另一个答案:设置侧边栏默认选中项。
结合这两个解决方案,我已经构建了一个2&3列共存样式的应用程序。
SwiftUI, selecting a row in a List programmatically
【讨论】:
【参考方案2】:这是一个使用自定义ViewModifier
的解决方案。它适用于 iOS 14.2、15.0 和 15.2。由于您使用的是SidebarListStyle
和Label
,因此我没有测试以前的版本。
测试项目:
enum Item: Hashable
case animals, animals2, settings, settings2
static var threeColumns = [Item.animals, .animals2]
static var twoColumns = [Item.settings, .settings2]
var title: String
switch self
case .animals:
return "animals"
case .animals2:
return "animals2"
case .settings:
return "settings"
case .settings2:
return "settings2"
var systemImage: String
switch self
case .animals:
return "tortoise"
case .animals2:
return "hare"
case .settings:
return "gear"
case .settings2:
return "gearshape"
struct ContentView: View
@State var selectedItem: Item?
var body: some View
NavigationView
List
Section(header: Text("Three columns"))
ForEach(Item.threeColumns, id: \.self) item in
NavigationLink(tag: item, selection: $selectedItem)
ItemsView()
label:
Label(item.title.capitalized, systemImage: item.systemImage)
Section(header: Text("Two columns"))
ForEach(Item.twoColumns, id: \.self) item in
NavigationLink(
destination: Text("I want to see here a single view, without detail"),
label:
Label(item.title, systemImage: item.systemImage)
)
.listStyle(SidebarListStyle())
.navigationBarTitle("App Menu")
struct ItemsView: View
let animals = ["Dog", "Cat", "Lion", "Squirrel"]
var body: some View
List
ForEach(animals, id: \.self) animal in
NavigationLink(
destination: DetailView(animal: animal))
Text(animal)
.listStyle(PlainListStyle())
.navigationTitle("Animals")
struct DetailView: View
var animal: String
var body: some View
VStack
Text("?")
.font(.title)
.padding()
Text(animal)
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
.previewLayout(.sizeThatFits)
private struct ColumnModifier: ViewModifier
let item: Item?
func body(content: Content) -> some View
if item == .settings || item == .settings2
content
EmptyView()
else
content
EmptyView()
DetailView(animal: "default")
【讨论】:
以上是关于SwiftUI 中具有不同列的侧边栏的主要内容,如果未能解决你的问题,请参考以下文章
在 UISplitViewController 中使用 SwiftUI 列表侧边栏
Vue.js - 使用 vuex 打开/关闭动态侧边栏思想不同的组件(导航栏到侧边栏)