как добавить разделитель панели инструментов для трехколоночного представления в жизненном цикле swiftUI

Я ищу способ создать панель инструментов для трехколоночного макета, такого как Mail.app. Кроме того, Notes.app использует почти ту же панель инструментов, с той лишь разницей, что между этими двумя приложениями важно то, что Notes.app выглядит как WindowStyle это HiddenTitleBarWindowStyle, а Mail.app выглядит как Default|TitleBarWindowStyle.

Следующее должно быть правдой:

  1. Если боковая панель свернута, отображается список и подробные сведения.
  2. Разделительная линия, отделяющая список от подробного представления, проходит через всю панель инструментов. (Этого можно добиться с помощью HiddenTitleBarWindowStyle)  боковая панель свернута - вид полностью разделен
  3. Если заголовок слишком длинный, чтобы поместиться в список навигации, вертикальная разделительная линия будет разорвана: список по-прежнему отделен от подробного представления, как и раньше, но теперь панель инструментов выглядит как DefaultWindowStyle с небольшой Divider() -подобной линией в Панель инструментов. боковая панель свернута - разделительная линия

Какая комбинация конфигурации WindowStyle, WindowToolbarStyle и .toolbar мне нужна для достижения этой настройки?

РЕДАКТИРОВАТЬ

Я заметил, что невозможно удалить разделительную линию, которую показывает Notes.app. Однако я не нашел ссылок на какой-либо такой элемент в документации.

Настраиваемая панель инструментов Notes.app

Пример кода

Я свел проблему к простому приложению, в основном с содержимым панели инструментов. В моем исходном коде я использую два вложенных NavigationView, а в примере я использовал только один NavigationView с двумя списками. Однако Toolbar результаты такие же.

Панель инструментов с DefaultWindowStyle

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, но ни один из них не переместил элемент в крайнее левое положение рядом с заголовком.

Стиль окна по умолчанию

Панель инструментов с HiddenTitleBarWindowStyle

@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 будет неправильным. Также при настройке Toolbar будет возможность удалить заголовок, что не должно быть возможным.

Стиль окна скрытого заголовка  Стиль окна скрытой строки заголовка со свернутой боковой панелью


person Enie    schedule 28.12.2020    source источник
comment
Что вы пробовали? Что не так с каждым? Где твой код?   -  person Asperi    schedule 29.12.2020
comment
Я обновил вопрос примерами кода. Возможно, это не все комбинации, которые я пробовал до сих пор, но это те, которые выглядят наиболее многообещающими. Впрочем, HiddenTitleBarWindowStyle похоже, что он никогда не сможет достичь цели, поскольку фальшивый заголовок кажется мне совершенно неправильным.   -  person Enie    schedule 29.12.2020


Ответы (1)


Стиль строки заголовка по умолчанию подходит, вам просто нужно прикрепить элементы панели инструментов к подпредставлениям вашего верхнего NavigationView, например:

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), но вы можете - просто не забудьте прикрепить те же элементы панели инструментов к элементам DetailView, поскольку его панель инструментов заменит панель инструментов Text, когда пользователь перемещается. (если вы не уверены, что я имею в виду, просто попробуйте, и вы быстро поймете, о чем я говорю :)

person Adam    schedule 31.12.2020
comment
вы знаете, что такое GIR ... Я потратил дни, чтобы понять это. с вашим пониманием это было вопросом двух минут попытки, пока я не получил именно то, что искал. добавление элементов панели инструментов во второй список и DetailView дало мне именно то разделение, которое я искал. Большое вам спасибо и желаю вам счастливого Нового года! - person Enie; 01.01.2021