How to integrate Mapbox SDK with SwiftUI
This is a working sample on how you can integrate the MGLMapView
with SwiftUI
.
When using UIViewRepresentable
you have to implement two delegates: makeUIView
that will return your view (in this case MGLMapView
) and updateUIView
which will receive the same view type as the one returned in makeUIView
(again MGLMapView
).
You can use this to experiment.
Also I recommend you get familiar with the React architecture to understand better the SwiftUI approach.
You can improve this sample by making ContentView
receive a styleURL, and trying different styles in the preview.
import Mapbox
import SwiftUI
struct ContentView : View {
var body: some View {
MapboxViewRepresentation(MGLStyle.streetsStyleURL)
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
struct MapboxViewRepresentation : UIViewRepresentable {
let styleURL: URL
init(_ styleURL: URL) {
self.styleURL = styleURL
}
func makeUIView(context: UIViewRepresentableContext<MapboxViewRepresentation>) -> MGLMapView {
let mapView = MGLMapView(frame: .zero, styleURL: styleURL)
return mapView
}
func updateUIView(_ uiView: MGLMapView, context: UIViewRepresentableContext<MapboxViewRepresentation>) {
}
}
UPDATE: Here is the official guide on how to integrate Mapbox with SwiftUI https://docs.mapbox.com/help/tutorials/ios-swiftui/
Mapbox autocomplete feature on iOS SwiftUI
Apparently for SwiftUI, you'll have to build the Autocomplete search feature on your own by using Mapbox Geocoding API. I made something simple, as shown below.
import SwiftUI
import Alamofire
struct AutocompleteSheet: View {
@State var searchText = ""
@State var SearchResults:[data]? = nil
var body: some View {
ScrollView {
HStack {
TextField(" Search locations", text: $searchText)
}
.onChange(of: searchText, perform: { value in
AutocompleteAPI()
})
}
if SearchResults != nil {
ForEach(0..<SearchResults!.count, id: \.self) { index in
HStack {
Button(action: {
print("which location: \(index)")
}) {
Image(systemName: "mappin.and.ellipse")
.foregroundColor(Color(.systemGray2))
Text("\(SearchResults![index].name)")
}
}
}
}
}
}
func AutocompleteAPI() -> Void {
let parameters:Parameters = [:]
APIClient.Autocomplete(query : searchText, completion:{(result) in
switch(result){
case .success(let Details):
print(Details)
if (Details.meta.statusCode == 200) {
print("Successful")
SearchResults = Details.data
}
else{
print("Fail")
}
case .failure(let error):
print("ERROR",error)
}
})
}
}
Mapbox iOS Navigation SDK Not Working With SwiftUI
For this case it should be used UIViewControllerRepresentable
, like below
struct NavView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> NavigationViewController {
var viewController: NavigationViewController
// Define two waypoints to travel between
let origin = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.9131752, longitude: -77.0324047), name: "Mapbox")
let destination = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.8977, longitude: -77.0365), name: "White House")
// Set options
let options = NavigationRouteOptions(waypoints: [origin, destination])
// Request a route using MapboxDirections.swift
Directions.shared.calculate(options) { (waypoints, routes, error) in
guard let route = routes?.first else { return }
// Pass the generated route to the the NavigationViewController
viewController = NavigationViewController(for: route)
viewController.modalPresentationStyle = .fullScreen
}
return viewController
}
func updateUIViewController(_ uiViewController: NavigationViewController, context: Context) {
}
}
Blank Map with Mapbox and SwiftUI
You need to set your MGLMapboxAccessToken
in Info.plist.
SwiftUI + MapBox integration messes up navbar
Updating Xcode from 11.3.1 to 11.4.1 did the trick.
Mapbox + SwiftUI: UI Refresh not propagating
Answering my own question here thanks to this post
https://github.com/mapbox/mapbox-maps-swiftui-demo/issues/3#issuecomment-623905509
In order for this to work it is necessary to update the UIView being rendered inside Mapview:
func updateUIView(_ uiView: MGLMapView, context: Context) {
updateAnnotations(uiView)
trackUser()
}
private func updateAnnotations(_ view: MGLMapView) {
if let currentAnnotations = view.annotations {
view.removeAnnotations(currentAnnotations)
}
view.addAnnotations(annotations)
}
Related Topics
After Getting Image from Uiimagepickercontroller, Uiimageview Rotates Image for iPhone 5
Generic Class with Class-Bound Constraint Cannot Be Parametrized by Class-Bound Protocol
How to Take a Substring to the First Index of a Character
Access Enum Associated Value as Optional
How to Convert This Date Format in Swift
Url Constructor Doesn't Work with Some Characters
Value' Is Inaccessible Due to 'Internal' Protection Level
Using the Swift If Let with Logical and Operator &&
Swift Cannot Output When Using Nstimer
Deleterowsatindexpaths Crashing
Using Tvposterimage in Tvuikit for Tvos 12
How to Group an Array of Image Urls Together in Firebase Realtime Database? (Swift)
A Method Without Parameters Is Calling for an Argument