Cómo configurar controles de un mapa con MapKit y SwiftUI
Misael Cuevas
03 abril, 20245min de lectura
MapKit
proporciona un conjunto de controles predefinidos que facilitan la interacción con un mapa. Estos son:
MapCompass
: Es una vista que muestra la orientación actual en el mapa.MapPitchToggle
: Permite cambiar la inclinación del mapa entre 2D y 3D.MapScaleView
: Muestra la distancia según el nivel de zoom realizado en el mapa.MapUserLocationButton
: Centra el mapa en la ubicación del usuario. Requiere permisos de localización.MapLocationCompass
: CombinaMapCompass
yMapUserLocationButton
. Disponible solo en watchOS.MapPitchSlider
: Permite ajustar la inclinación del mapa mediante un control deslizante. Disponible solo en macOS.MapZoomStepper
: Permite acercar (zoom in) o alejar (zoom out) un área en el mapa. Disponible solo en macOS.
Para utilizar estos controles de manera rápida y sencilla en un mapa, puedes emplear el modificador .mapControls
. Por ejemplo:
import MapKit// 1import SwiftUIstruct MapView: View {var body: some View {// 2Map()// 3.mapControls {// 4MapScaleView()MapCompass()MapPitchToggle()}}}
- Se importa el framework de
MapKit
. - Se agrega
Map
a la vista. - Se aplica el modificador
.mapControls
aMap
. - Se añaden los controles a utilizar en
Map
.
Algunos puntos a destacar con respecto a este ejemplo:
- Algunos controles pueden necesitar que el usuario amplíe o gire el mapa para ser visibles.
- El orden de los controles en el código no necesariamente coincide con su posición en la interfaz.
- Por defecto, los controles están ubicados en ciertas posiciones en el mapa.
- Si intentas añadir vistas de SwiftUI no designadas como controles de mapa, por ejemplo un
Button
, estas no se mostrarán.
Esto se debe a que el modificador .mapControls
gestiona automáticamente la posición y comportamiento de los controles en el mapa, limitando la adición de vistas no especificadas.
Para modificar ciertos comportamientos de los controles tienes que hacer uso de otros modificadores que verás a continuación.
Visibilidad
Utilizando el modificador .mapControlVisibility(_ visibility: Visibility)
, puedes establecer la visibilidad de un control específico o de todos ellos. Los valores que puedes asignar son:
automatic
: El control puede estar visible/oculto según su comportamiento.visible
: El control puede estar visible.hidden
: El control puede estar oculto.
Por ejemplo, para mostrar todos los controles:
Map().mapControls {MapScaleView()MapPitchToggle()}.mapControlVisibility(.visible)
O ajustar la visibilidad de cada control por separado:
Map().mapControls {MapScaleView().mapControlVisibility(.hidden)MapPitchToggle().mapControlVisibility(.visible)}
Personalización
Para algunos controles, puedes personalizar su forma, color y tamaño utilizando modificadores como .buttonBorderShape
, .tint
y .controlSize
. Por ejemplo:
Map().mapControls {MapPitchToggle()MapUserLocationButton()}.buttonBorderShape(.circle).tint(.red).controlSize(.large)
Posicionamiento
No existe un modificador específico para establecer la posición de los controles en el mapa mientras se utiliza .mapControls
. Sin embargo, puedes lograrlo utilizando los controles de forma independiente al mapa. Para ello, primero crea una variable que utilice el property wrapper @Namespace
para conectar los controles con el mapa. Por ejemplo:
@Namespace var scope
Luego, asigna esta variable al inicializador del mapa:
Map(scope: scope)
Finalmente, agrega tus controles utilizando alguna vista contenedora como un VStack
o superponiéndolos al mapa con el modificador .overlay
y el modificador .mapScope
:
Map(scope: scope)// 1.mapControls { }// 2.overlay(alignment: .topLeading) {// 3VStack {MapCompass(scope: scope)MapPitchToggle(scope: scope)}.mapControlVisibility(.visible)}// 4.mapScope(scope)
- Se agrega el modificador
.mapControls
vacío para evitar queMap
agregue los controles que utiliza por defecto y evitar duplicidad con los que añades de forma manual. - Se utiliza el modificador
.overlay
para superponer los controles en el mapa y ubicarlos en la esquina superior izquierda. - Se añade un
VStack
con los controles asignándoles la variablescope
para asociarlos con el mapa. Además, coinciden el orden de los controles en la interfaz según se añadió en el código. - Se agrega el modificador
.mapScope
a la vista contenedora del mapa y los controles, en este caso seria el propioMap
.
Al usar los controles de forma independiente al mapa, se puede perder la estética visual proporcionada por el modificador .mapControls
, pero puedes recuperarla fácilmente ajustando el diseño de los controles.
Map(scope: scope).mapControls { }.overlay(alignment: .topLeading) {VStack {MapCompass(scope: scope)MapPitchToggle(scope: scope)}.padding(.leading, 15).mapControlVisibility(.visible).buttonBorderShape(.roundedRectangle)}.mapScope(scope)