DEV Community

GoyesDev
GoyesDev

Posted on

[SUI] NavigationLink

NavigationStack maneja una pila de vistas. NavigationLink es un componente que crea un botón con cierta etiqueta, que el usuario puede presionar para agregar una vista en la pila.

  • init(_:destination:). titleKey es el texto de la etiqueta. destination es la vista a presentar.
  • init(_:value:). titleKey es el texto de la etiqueta. value es un valor opcional de tipo Hashable asociado a una vista a presentar. nil desactiva el enlace.
struct NextView: View {
  var body: some View {
    ZStack {
      Color.red.opacity(0.7)
      Text("Vista #2")
    }
    .navigationTitle("Segunda vista")
    .navigationSubtitle("Este es el destino de la primera")
  }
}
Enter fullscreen mode Exit fullscreen mode
struct ContentView: View {

  var body: some View {
    NavigationStack {
      ZStack {
        Color.blue.opacity(0.7)
        Text("Vista #1")
      }
      .navigationTitle("Primera vista")
      .navigationSubtitle("Desde acá puedo navegar")
      .toolbar {
        NavigationLink(destination: {
          NextView()
        }) {
          Image(systemName: "paperplane")
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Notar que al presionar el botón del toolbar se efectua la transición. Sin embargo, desde iOS 26 ya no aparece el título de la vista anterior al lado del botón de retroceso.

Creación de un botón de retroceso personalizado

Para empezar, se debe ocultar el botón de retroceso por defecto de la barra de navegación con navigationBarBackButtonHidden(_:).

struct NextView: View {
  var body: some View {
    ZStack {
      Color.red.opacity(0.7)
      Text("Vista #2")
    }
    .navigationTitle("Segunda vista")
    .navigationSubtitle("Este es el destino de la primera")
    .navigationBarBackButtonHidden()
  }
}
Enter fullscreen mode Exit fullscreen mode

Luego, se puede eliminar la vista del stack de navegación por medio de las siguientes variables de ambiente:

  • dismiss. Acción de tipo DismissAction que cierra la vista presentada. La acción se puede ejecutar como un closure.
  • isPresented. Variable de ambiente que indica que la vista se está presentando.
struct NextView: View {
  @Environment(\.dismiss) private var dismiss: DismissAction

  var body: some View {
    ZStack {
      Color.red.opacity(0.7)
      Text("Vista #2")
    }
    .navigationTitle("Segunda vista")
    .navigationSubtitle("Este es el destino de la primera")
    .navigationBarBackButtonHidden()
    .toolbar {
      ToolbarItem(placement: .topBarLeading) {
        Button("Go back", systemImage: "chevron.backward.circle") {
          dismiss()
        }
        .tint(.red)
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Patrón maestro-detalle

En el modo "apilado" del patrón maestro-detalle, se suele tener una lista "maestra" con unos títulos de una colección y, al pulsar alguna de las filas, se navega hacia el "detalle" mostrando la información adicional del elemento.

Esto se puede implementar en SwiftUI con un List, donde cada elemento es un NavigationLink, que generalmente tiene una etiqueta simple (e.g. Text o Label), que tiene como destino la vista detalle que recibe el elemento de la lista seleccionado.

struct DetailView: View {
  let person: Person

  var body: some View {
    VStack {
      Text("Esta es la vista detalle para el siguiente personaje:")
      Text("\(person.name) \(person.lastname)")
    }
    .navigationTitle("Detalle")
    .navigationBarTitleDisplayMode(.inline)
  }
}
Enter fullscreen mode Exit fullscreen mode
struct ContentView: View {

  @State private var searchText: String = ""

  private var filteredPeople: [Person] {
    if searchText.isEmpty {
      people
    } else {
      people.filter {
        $0.name.localizedStandardContains(searchText) }
    }
  }

  var body: some View {
    NavigationStack {
      List(filteredPeople) { person in
        NavigationLink {
          DetailView(person: person)
        } label: {
          //Text("\(person.name) \(person.lastname)")
          Label("\(person.name) \(person.lastname)", systemImage: "person")
        }
      }
      .navigationTitle("Personas")
      .searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .automatic), prompt: "¿A quién busca?")
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Manipulando el stack de navegación

Se puede cambiar manualmente la pila de vistas de navegación así:

  1. Al crear un NavigationLink se debe usar el constructor init(_:value:) para señalar cuál es el identificador Hashable asociado a la vista destino deseada. Se debe crear un tipo de dato diferente por cada destino.
  2. Se debe modificar el NavigationStack con navigationDestination(for:destination:) que asocia el tipo de dato de un identificador (data) a una vista de destino (destination).
  3. Al ejecutar una transición, presionando el NavigationLink, NavigationStack agrega el value a un NavigationPath, que debe ser un Binding (i.e. @State o @Published).

NavigationPath incluye las siguientes propiedades para manejar los valores:


Bibliografía

Top comments (0)