如何在swiftUI生命周期中为三栏视图添加工具栏分隔线 [英] how to add a toolbar divider for a three column view in swiftUI life cycle

查看:52
本文介绍了如何在swiftUI生命周期中为三栏视图添加工具栏分隔线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种实现三栏布局(如Mail.app)的工具栏的方法.另外,Notes.app使用几乎相同的工具栏,这两个应用之间的唯一重要区别在于,Notes.app的 WindowStyle 看起来是 HiddenTitleBarWindowStyle ,而Mail.app看起来就像 Default | TitleBarWindowStyle .

I am looking for a way to achieve a Toolbar for a three column layout like Mail.app. Also the Notes.app uses almost the same Toolbar with the only important difference between the two apps being that Notes.app looks like it's WindowStyle is a HiddenTitleBarWindowStyle and Mail.app looks like a Default|TitleBarWindowStyle.

以下应为真:

  1. 如果侧边栏处于折叠状态,则会显示一个列表和详细信息视图
  2. 将列表与详细信息视图分开的分隔线一直贯穿工具栏.(这可以通过 HiddenTitleBarWindowStyle 来实现)
  3. 如果标题"太长而无法放入导航列表,则垂直分隔线将被打破:列表仍然像以前一样从详细信息视图"中进行划分,但是现在工具栏看起来像是 DefaultWindowStyle 在工具栏中只有一条类似 Divider()的细线.
  1. If the sidebar is collapsed there is a list and detail view
  2. The dividing line that separates the list from the detail view goes all the way up through the toolbar. (This could be achieved with a HiddenTitleBarWindowStyle)
  3. If the Title is too long to fit into the navigation list, the vertical dividing line will be broken: The list is still divided from the Detail View as before, but now the Toolbar looks like a DefaultWindowStyle with only a small Divider()-like line in the Toolbar.

我需要配置 WindowStyle WindowToolbarStyle .toolbar 哪些配置?

Which combination of WindowStyle, WindowToolbarStyle and .toolbar configuration do I need to achieve this setup?

我注意到无法删除Notes.app显示的分隔线.我在文档中没有找到对任何此类元素的引用.

I noticed that it is not possible to remove the divider line that Notes.app shows. I have not found a references to any such element in the docs though.

我将问题简化为一个主要包含工具栏内容的简单应用程序.在我的原始代码中,我使用了两个嵌套的 NavigationView ,而在本示例中,我仅使用了一个带有两个列表的 NavigationView .但是工具栏结果相同.

I have distilled the problem down to a simple app with mostly toolbar content. In my original code I use two nested NavigationViews, while for the example I used only one NavigationView with two Lists. However the Toolbar results are the same.

import SwiftUI

@main
struct ToolbarTestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView(titleBarIsHidden: true)
        }
        .windowToolbarStyle(UnifiedWindowToolbarStyle())
        .commands {
            SidebarCommands()
        }
    }
}

struct ContentView: View {
    @State var destination: String = "Toolbar Test"
    @State var detail: String = ""
    
    var body: some View {
        NavigationView {
            List {
                Button(action: {self.destination = "Item with the identifier:  1"}, label: {
                    Text("Item 1")
                })
                .buttonStyle(DefaultButtonStyle())
                Button(action: {self.destination = "Item 2"}, label: {
                    Text("Item 2")
                })
                .buttonStyle(DefaultButtonStyle())
            }
            .listStyle(SidebarListStyle())
            List {
                NavigationLink(
                    destination: DetailView(text: "\(destination) – \(detail)").onAppear{self.detail = "Detail 1"},
                    label: {
                        Text("\(destination) – Detail 1")
                    })
                NavigationLink(
                    destination: DetailView(text: "\(destination) – \(detail)").onAppear{self.detail = "Detail 2"},
                    label: {
                        Text("\(destination) – Detail 2")
                    })
            }
            .listStyle(InsetListStyle())
            Text("\(destination) – \(detail)")
        }
        .navigationTitle(destination)
        .navigationSubtitle(detail)
        .toolbar(id: "nav") {
            ToolbarItem(id: "plus", placement: ToolbarItemPlacement.principal, showsByDefault: true) {
                HStack {
                    Button(action: {print("pressed")}, label: {
                        Image(systemName: "plus.circle")
                    })
                }
            }
            ToolbarItem(id: "spacer", placement: ToolbarItemPlacement.confirmationAction, showsByDefault: true) {
                HStack {
                    Spacer()
                }
            }
            ToolbarItem(id: "sidebar.end", placement: ToolbarItemPlacement.confirmationAction, showsByDefault: true) {
                Button(action: {print("pressed")}, label: {
                    Image(systemName: "sidebar.right")
                })
            }
        }
    }
}

此示例将生成一个 Toolbar ,该工具栏将永远不会显示将整个 Toolbar 分为两部分的分隔线.同样,第一个 ToolbarItem 位于 Toolbar 的中心.我尝试了所有 ToolbarItemPlacement ,但没有一个导致该项移动到标题附近的最左侧.

This example will result in a Toolbar that will never show the divider line that splits the whole Toolbar in two parts. Also the first ToolbarItem is positioned in the center of the Toolbar. I tried all ToolbarItemPlacement but none caused the item to move to the far left adjacent to the title.

@main
struct ToolbarTestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentViewForHiddenTitleBar()
        }
        .windowStyle(HiddenTitleBarWindowStyle()) // added hidden title style
        .windowToolbarStyle(UnifiedWindowToolbarStyle())
        .commands {
            SidebarCommands()
        }
    }
}

struct ContentViewForHiddenTitleBar: View {
    @State var destination: String = "Toolbar Test"
    @State var detail: String = ""
    
    var body: some View {
        NavigationView {
            List {
                Button(action: {self.destination = "Item with the identifier:  1"}, label: {
                    Text("Item 1")
                })
                .buttonStyle(DefaultButtonStyle())
                Button(action: {self.destination = "Item 2"}, label: {
                    Text("Item 2")
                })
                .buttonStyle(DefaultButtonStyle())
            }
            .listStyle(SidebarListStyle())
            // add geometry reader to trim title width in toolbar
            GeometryReader { geometry in
                List {
                    NavigationLink(
                        destination: DetailView(text: "\(destination) – \(detail)").onAppear{self.detail = "Detail 1"},
                        label: {
                            Text("\(destination) – Detail 1")
                        })
                    NavigationLink(
                        destination: DetailView(text: "\(destination) – \(detail)").onAppear{self.detail = "Detail 2"},
                        label: {
                            Text("\(destination) – Detail 2")
                        })
                }
                // there is no title anymore so let's fake it.
                .toolbar(id: "list navigation") {
                    ToolbarItem(id: "title", placement: ToolbarItemPlacement.navigation, showsByDefault: true) {
                        VStack(alignment: .leading) {
                            Text(destination)
                                .font(.headline)
                                .frame(maxWidth: .infinity, alignment: .leading)
                            Text(detail)
                                .font(.subheadline)
                                .opacity(0.6)
                                .frame(maxWidth: .infinity, alignment: .leading)
                        }
                        .frame(width: geometry.size.width)
                    }
                }
            }
            .listStyle(InsetListStyle())
            Text("\(destination) – \(detail)")
        }
        .navigationTitle(destination)
        .navigationSubtitle(detail)
        .toolbar(id: "nav") {
            // primary action will place the item next to the divider line.
            ToolbarItem(id: "plus", placement: ToolbarItemPlacement.primaryAction, showsByDefault: true) {
                HStack {
                    Button(action: {print("pressed")}, label: {
                        Image(systemName: "plus.circle")
                    })
                }
            }
            ToolbarItem(id: "spacer", placement: ToolbarItemPlacement.confirmationAction, showsByDefault: true) {
                HStack {
                    Spacer()
                }
            }
            ToolbarItem(id: "sidebar.end", placement: ToolbarItemPlacement.confirmationAction, showsByDefault: true) {
                Button(action: {print("pressed")}, label: {
                    Image(systemName: "sidebar.right")
                })
            }
        }
    }
}

此示例将导致一个 Toolbar (工具栏),该工具栏始终显示全高分隔线.即使标题太长.因此,添加了 GeometryReader .这很好,直到侧边栏折叠起来. ToolbarItems 的位置不正确.同样,在自定义工具栏时,也有可能删除标题,而这是不可能的.

This example will result in a Toolbar that will always show a full height divider. Even if the title is too long. Therefore a GeometryReader was added. This is fine until the sidebar will collapse. The placement of ToolbarItems will not be correct. Also when customising the Toolbar there would be the possibility to remove the title, which should not be possible.

推荐答案

默认的标题栏样式很好,您只需将工具栏项附加到顶部NavigationView的子视图即可,例如:

The default title bar style is fine, you just need to attach your toolbar items to the subviews of your top NavigationView, e.g.:

var body: some View {
    NavigationView {
        
        List {
            ...
        }
        .listStyle(SidebarListStyle())
        .toolbar {
            ToolbarItem {
                Button(action: { }, label: {
                    Image(systemName: "sidebar.right")
                })
            }
        }
        
        List {
            ...
        }
        .listStyle(InsetListStyle())
        .toolbar {
            ToolbarItem {
                Button(action: { }, label: {
                    Image(systemName: "plus.circle")
                })
            }
        }
        
        Text("\(destination) – \(detail)")
    }
    .navigationTitle(destination)
    .navigationSubtitle(detail)
}

我没有在第三列( Text )上附加任何工具栏项,但是可以-只需确保将相同的工具栏项附加到DetailViews,因为它的工具栏将替换Text的用户导航时的工具栏.(如果不确定我的意思,请尝试一下,您将很快了解我在说什么:)

I didn’t attach any toolbar items to the third column (the Text) but you can — just be sure to attach the same toolbar items to your DetailViews, as its toolbar will replace the Text’s toolbar when the user navigates. (if you’re not sure what I mean, just try it and you’ll quickly see what I’m talking about :)

这篇关于如何在swiftUI生命周期中为三栏视图添加工具栏分隔线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆