Я ищу способ создать панель инструментов для трехколоночного макета, такого как Mail.app. Кроме того, Notes.app использует почти ту же панель инструментов, с той лишь разницей, что между этими двумя приложениями важно то, что Notes.app выглядит как WindowStyle
это HiddenTitleBarWindowStyle
, а Mail.app выглядит как Default|TitleBarWindowStyle
.
Следующее должно быть правдой:
- Если боковая панель свернута, отображается список и подробные сведения.
- Разделительная линия, отделяющая список от подробного представления, проходит через всю панель инструментов. (Этого можно добиться с помощью
HiddenTitleBarWindowStyle
) - Если заголовок слишком длинный, чтобы поместиться в список навигации, вертикальная разделительная линия будет разорвана: список по-прежнему отделен от подробного представления, как и раньше, но теперь панель инструментов выглядит как
DefaultWindowStyle
с небольшойDivider()
-подобной линией в Панель инструментов.
Какая комбинация конфигурации WindowStyle
, WindowToolbarStyle
и .toolbar
мне нужна для достижения этой настройки?
РЕДАКТИРОВАТЬ
Я заметил, что невозможно удалить разделительную линию, которую показывает 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
будет возможность удалить заголовок, что не должно быть возможным.
HiddenTitleBarWindowStyle
похоже, что он никогда не сможет достичь цели, поскольку фальшивый заголовок кажется мне совершенно неправильным. - person Enie   schedule 29.12.2020