メインコンテンツまでスキップ

SwiftUI - Locate Me

This example demonstrates a SwiftUI implementation of a "Locate Me" functionality using the Mapbox Maps SDK for iOS. The LocateMeExample struct includes a Map component with a Puck2D element, allowing users to locate themselves on the map.

The user's location is tracked through a Viewport state variable, which can be adjusted to follow the user's location at varying zoom levels and bearing angles.

The LocateMeButton struct defines a button that users can interact with to toggle between different map tracking modes, enabling them to focus on their location, follow their movement, or support an idle state. The button transitions smoothly between different states using animation effects. This example showcases a user-friendly way to incorporate location tracking and map interaction in a SwiftUI environment.

iOS Examples App Available

This example code is part of the Maps SDK for iOS Examples App, a working iOS project available on Github. iOS developers are encouraged to run the examples app locally to interact with this example in an emulator and explore other features of the Maps SDK.

See our Run the Maps SDK for iOS Examples App tutorial for step-by-step instructions.

LocateMeExample.swift
import SwiftUI
import MapboxMaps

@available(iOS 14.0, *)
struct LocateMeExample: View {
@State var viewport: Viewport = .followPuck(zoom: 13, bearing: .constant(0))

var body: some View {
Map(viewport: $viewport) {
Puck2D(bearing: .heading)
}
.mapStyle(.standard)
.ignoresSafeArea()
.safeOverlay(alignment: .trailing) {
LocateMeButton(viewport: $viewport)
}
}
}

@available(iOS 14.0, *)
struct LocateMeButton: View {
@Binding var viewport: Viewport

var body: some View {
Button {
withViewportAnimation(.default(maxDuration: 1)) {
if isFocusingUser {
viewport = .followPuck(zoom: 16.5, bearing: .heading, pitch: 60)
} else if isFollowingUser {
viewport = .idle
} else {
viewport = .followPuck(zoom: 13, bearing: .constant(0))
}
}
} label: {
Image(systemName: imageName)
.transition(.scale.animation(.easeOut))
}
.safeContentTransition()
.buttonStyle(MapFloatingButtonStyle())
}

private var isFocusingUser: Bool {
return viewport.followPuck?.bearing == .constant(0)
}

private var isFollowingUser: Bool {
return viewport.followPuck?.bearing == .heading
}

private var imageName: String {
if isFocusingUser {
return "location.fill"
} else if isFollowingUser {
return "location.north.line.fill"
}
return "location"

}
}

@available(iOS 13.0, *)
private extension View {
func safeContentTransition() -> some View {
if #available(iOS 17, *) {
return self.contentTransition(.symbolEffect(.replace))
}
return self
}
}

@available(iOS 14.0, *)
struct LocateMeExample_Preview: PreviewProvider {
static var previews: some View {
LocateMeExample()
}
}
このexampleは役に立ちましたか?