Se puede agregar elementos a y configurar la barra de navegación con los siguientes modificadores:
-
toolbar(id:content:): Agrega los elementos decontenta un toolbar, que puede ser una colección de vistas simples, o una colección de vistas donde cada elemento está envuelto con unToolbarItem.ides opcional y permite almacenar la última configuración de la barra. -
toolbarVisibility(_:for:): Muestra u oculta una barra (segúnvisibility).for, de tipoToolbarPlacement(que puede serautomatic,buttomBar,navigationBar,tabBarywindowToolbar), representa las barras a modificar. -
toolbarBackgroundVisibility(_:for:): Configura la visibilidad de la barra. -
toolbar(removing:): Elimina un elemento del toolbar añadido por defecto, de tipoToolbarDefaultItemKindque puede sersidebarToggle(agregado porNavigationSplitView),search(añadido porView/searchable(text:isPresented:placement:prompt)) ytitle
En el siguiente ejemplo se agrega un botón en la barra de navegación:
struct ContentView: View {
let scrums: [DailyScrum]
var body: some View {
NavigationStack {
List(scrums) { scrum in
NavigationLink {
Text(scrum.title)
} label: {
CardView(scrum: scrum)
}
.listRowBackground(scrum.theme)
}
// ⚠️ Se cambió el navigationBar para que sea .inline
// y así se pueda ver mejor el toolbar
.navigationBarTitleDisplayMode(.inline)
.navigationTitle("Daily Scrums")
.toolbar {
// ⚠️ Se definen los elementos dentro de la barra
Button(action: {}) {
Image(systemName: "plus")
}
.accessibilityLabel("New Scrum")
}
}
}
}
struct DailyScrum: Identifiable {
let id: UUID = UUID()
let theme: Color
let title: String
let participants: Int
let length: Int
}
struct CardView: View {
let scrum: DailyScrum
var body: some View {
VStack(alignment: .leading) {
Text(scrum.title)
.fontWeight(.bold)
HStack {
HStack {
Image(systemName: "person.3")
Text(scrum.participants.description)
}
.accessibilityLabel("Number of participants")
Spacer()
HStack {
Text(scrum.length.description)
Image(systemName: "clock")
}
.accessibilityLabel("Meeting length")
}
.padding(.top)
.font(.caption)
.foregroundStyle(.primary)
}
.padding(.horizontal)
}
}
Puedo agregar tantos botones como sean necesarios:
.toolbar {
Button(action: {}) {
Image(systemName: "plus")
}
.accessibilityLabel("New Scrum")
Button(action: {}) {
Image(systemName: "trash")
}
.accessibilityLabel("Remove Scrum")
}
Envolviendo en ToolbarItem
Como se mencionó arriba, los elementos del toolbar pueden envolverse con ToolbarItem. No es obligatorio, aunque la estrategia a usar debe ser uniforme en toda la colección: es decir, o todos los elementos están envueltos con ToolbarItem o ninguno lo está. Se usa el siguiente constructor:
-
init(id:placement:content:):ides un identificador opcional para almacenar la configuración del item.placement, de tipoToolbarItemPlacement, es la sección dentro del toolbar donde vivirá.
Se usa ToolbarItem para configurar con más precisión la forma como se pintan en pantalla. Por ejemplo:
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Button(action: {}) {
Image(systemName: "plus")
}
.accessibilityLabel("New Scrum")
}
ToolbarItem {
Button(action: {}) {
Image(systemName: "trash")
}
.accessibilityLabel("Remove Scrum")
}
}
Hay que tener en cuenta que el uso de ToolbarItem debe ser uniforme: o todos los elementos de la colección lo tienen, o ninguno. De lo contrario, aparece el siguiente error de compilación:
Failed to produce diagnostic for expression; please submit a bug report (https://swift.org/contributing/#reporting-bugs)
ToolbarItemGroup
Se pueden definir varios botones a la vez con ToolbarItemGroup.
-
init(placement:content:).placementes de tipoToolbarItemPlacemente indica la región de la pantalla donde vivirán los elementos definidos porcontent.
Al crear ToolbarItem para configurar los botones de una barra inferior (bottomBar), estos estarán alineados al centro por defecto.
.toolbar {
ToolbarItem(placement: .bottomBar) {
Button(action: {}) {
Image(systemName: "plus")
}
.accessibilityLabel("New Scrum")
}
ToolbarItem(placement: .bottomBar) {
Button(action: {}) {
Image(systemName: "trash")
}
.accessibilityLabel("Remove Scrum")
}
}
Sin embargo, al usar un ToolbarItemGroup, se pueden alinear los elementos a un extremo usando Spacer.
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
Spacer()
Button(action: {}) {
Image(systemName: "plus")
}
.accessibilityLabel("New Scrum")
Button(action: {}) {
Image(systemName: "trash")
}
.accessibilityLabel("Remove Scrum")
}
}
Alineando ToolbarItems según su función
Aunque se puede establecer de forma explícita la ubicación de un ToolbarItem (e.g. topBarLeading y topBarTrailing) , se puede definir la función del botón y dejar que el sistema se encargue de ubicarlo.
Por ejemplo, primaryAction es una acción usada con mucha frecuencia en el contexto actual de la pantalla que está viendo el usuario. Esta acción aparece en el extremo final ("trailing") de la barra de navegación en iOS y en el extremo inicial ("leading") del toolbar en MacOS.
Por otro lado, secondaryAction es otro tipo de acción que también se usa con frecuencia en el contexto actual de la pantalla, pero que no es requerido para funcionar.
NOTA DE VITAL IMPORTANCIA: Los botones con ubicación secondaryAction NO VAN A FUNCIONAR si se crean con el inicializador init(action:label:). Debe usarse el inicializador: init(_:systemImage:role:action:)
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(action: {
print("Adding")
}) {
Image(systemName: "plus")
}
}
ToolbarItem(placement: .secondaryAction) {
Button("Removing", systemImage: "trash") {
print("Removing")
}
.accessibilityLabel("Remove Scrum")
}
}
Rol del toolbar
Los botones del toolbar pueden tener funciones diferentes según el contexto de la pantalla. A esto se le conoce como ToolbarRole y puede ser configurado con toolbarRole(_:). Por defecto está en automatic que, al ser usado dentro de un NavigationStack querría decir que adquiere un rol de navigationStack. Sin embargo, puede ser que las funciones del toolbar estén relacionadas con la edición del contenido de la pantalla actual. En ese caso, se puede usar el rol editor.
Si se usa el rol por defecto o navigationStack:
Si se usa el rol de editor:
Distanciando botones
Dos ToolbarItem con la misma ubicación estarán agrupados por defecto.
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button(action: {
print("Adding")
}) {
Image(systemName: "plus")
}
}
ToolbarItem(placement: .topBarTrailing) {
Button("Removing", systemImage: "trash") {
print("Removing")
}
.accessibilityLabel("Remove Scrum")
}
}
Para separarlos se usa ToolbarSpacer que puede tener tamaño fijo (fixed) o rellenar tanto espacio como pueda (flexible).
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button(action: {
print("Adding")
}) {
Image(systemName: "plus")
}
}
ToolbarSpacer(.fixed, placement: .topBarTrailing)
ToolbarItem(placement: .topBarTrailing) {
Button("Removing", systemImage: "trash") {
print("Removing")
}
.accessibilityLabel("Remove Scrum")
}
}
Se puede usar ToolbarItemGroup en conjunto con ToolbarSpacer para crear grupos aislados dentro del toolbar:
.toolbar {
ToolbarItemGroup(placement: .topBarTrailing) {
Button(action: {
print("Adding")
}) {
Image(systemName: "plus")
}
Button("Drawing", systemImage: "pencil") {
print("Dibujando")
}
}
ToolbarSpacer(.flexible, placement: .topBarTrailing)
ToolbarItem(placement: .topBarTrailing) {
Button("Removing", systemImage: "trash") {
print("Removing")
}
.accessibilityLabel("Remove Scrum")
}
}
ToolbarSpacer con tamaño flexible sirve para separar ToolbarItems hacia los extremos del bottomBar:
.toolbar {
ToolbarItem(placement: .bottomBar) {
Button(action: {
print("Adding")
}) {
Image(systemName: "plus")
}
}
ToolbarSpacer(.flexible, placement: .bottomBar)
ToolbarItem(placement: .bottomBar) {
Button("Removing", systemImage: "trash") {
print("Removing")
}
.accessibilityLabel("Remove Scrum")
}
}
.toolbar {
ToolbarSpacer(.flexible, placement: .bottomBar)
ToolbarItem(placement: .bottomBar) {
Button("Removing", systemImage: "trash") {
print("Removing")
}
.accessibilityLabel("Remove Scrum")
}
}
Alineando Toolbar con Navigationbar
Usando toolbarTitleDisplayMode(_:) se puede alinear la barra de navegación con el toolbar con los modos inline e inlineLarge:
.navigationTitle("Daily Scrums")
.navigationSubtitle("Testing toolbar")
.toolbarTitleDisplayMode(.inlineLarge)
.toolbar {
ToolbarItemGroup(placement: .topBarTrailing) {
Button(action: {
print("Adding")
}) {
Image(systemName: "plus")
}
Button("Drawing", systemImage: "pencil") {
print("Dibujando")
}
}
ToolbarSpacer(.flexible, placement: .topBarTrailing)
ToolbarItem(placement: .topBarTrailing) {
Button("Removing", systemImage: "trash") {
print("Removing")
}
.accessibilityLabel("Remove Scrum")
}
}
Título y subtítulo del toolbar
Solo cuando el ToolbarTitleDisplayMode esté configurado en large (o automatic), se puede poner un título y un subtítulo al toolbar al usar las ubicaciones principal, title y largeTitle; y subtitle y largeSubtitle, respectivamente.
.navigationTitle("Daily Scrums")
.navigationSubtitle("Testing toolbar")
.toolbar {
ToolbarItem(placement: .title) {
Text("Título")
}
ToolbarItem(placement: .subtitle) {
Text("Subtítulo")
}
ToolbarItemGroup(placement: .topBarTrailing) {
Button(action: {
print("Adding")
}) {
Image(systemName: "plus")
}
Button("Drawing", systemImage: "pencil") {
print("Dibujando")
}
}
ToolbarSpacer(.flexible, placement: .topBarTrailing)
ToolbarItem(placement: .topBarTrailing) {
Button("Removing", systemImage: "trash") {
print("Removing")
}
.accessibilityLabel("Remove Scrum")
}
}
Menú
Para agregar manualmente un menú desplegable en el toolbar, en lugar de un Button, se debe agregar un Menu envuelto en un ToolbarItem.
.toolbar() {
ToolbarItem(placement: .topBarTrailing) {
Menu {
Button("Draw", systemImage: "pencil") {
print("Drawing")
}
Button("Call", systemImage: "phone") {
print("Calling")
}
} label: {
Image(systemName: "ellipsis.circle")
}
}
ToolbarSpacer(placement: .topBarTrailing)
ToolbarItem(id: "removing", placement: .destructiveAction) {
Button("Removing", systemImage: "trash") {
print("Removing")
}
.accessibilityLabel("Remove Scrum")
}
}


















Top comments (0)