diff --git a/android/src/main/java/org/maplibre/reactnative/components/camera/MLRNCamera.java b/android/src/main/java/org/maplibre/reactnative/components/camera/MLRNCamera.java index 2e6e95d81..a10a66ce7 100644 --- a/android/src/main/java/org/maplibre/reactnative/components/camera/MLRNCamera.java +++ b/android/src/main/java/org/maplibre/reactnative/components/camera/MLRNCamera.java @@ -2,6 +2,7 @@ import android.content.Context; import android.location.Location; +import android.util.Log; import org.maplibre.android.camera.CameraPosition; import org.maplibre.android.camera.CameraUpdate; @@ -11,13 +12,9 @@ import org.maplibre.android.geometry.VisibleRegion; import org.maplibre.android.location.OnCameraTrackingChangedListener; import org.maplibre.android.location.modes.CameraMode; -import org.maplibre.android.location.modes.RenderMode; import org.maplibre.android.maps.MapLibreMap; import org.maplibre.android.maps.Style; -import org.maplibre.android.location.LocationComponent; -import org.maplibre.android.location.LocationComponentOptions; -import org.maplibre.android.location.LocationComponentActivationOptions; -// import org.maplibre.android.plugins.locationlayer.LocationLayerPlugin; + import org.maplibre.reactnative.components.AbstractMapFeature; import org.maplibre.reactnative.components.location.LocationComponentManager; import org.maplibre.reactnative.components.mapview.MLRNMapView; @@ -31,8 +28,6 @@ import org.maplibre.reactnative.location.UserTrackingState; import org.maplibre.reactnative.utils.GeoJSONUtils; -import org.maplibre.reactnative.R; - import org.maplibre.reactnative.events.constants.EventTypes; import com.facebook.react.bridge.WritableMap; @@ -87,12 +82,12 @@ public class MLRNCamera extends AbstractMapFeature { private LocationManager.OnUserLocationChange mLocationChangeListener = new LocationManager.OnUserLocationChange() { @Override public void onLocationChange(Location nextLocation) { - if (getMapboxMap() == null || mLocationComponentManager == null || !mLocationComponentManager.hasLocationComponent() || (!mFollowUserLocation)) { - return; - } + if (getMapboxMap() == null || mLocationComponentManager == null || !mLocationComponentManager.hasLocationComponent() || (!mFollowUserLocation)) { + return; + } - mUserLocation.setCurrentLocation(nextLocation); - sendUserLocationUpdateEvent(nextLocation); + mUserLocation.setCurrentLocation(nextLocation); + sendUserLocationUpdateEvent(nextLocation); } }; @@ -236,12 +231,7 @@ private CameraPosition getUserLocationUpdateCameraPosition(double zoomLevel) { } } - return new CameraPosition.Builder() - .target(center) - .bearing(getDirectionForUserLocationUpdate()) - .tilt(mPitch) - .zoom(zoomLevel) - .build(); + return new CameraPosition.Builder().target(center).bearing(getDirectionForUserLocationUpdate()).tilt(mPitch).zoom(zoomLevel).build(); } private double getDirectionForUserLocationUpdate() { @@ -260,7 +250,7 @@ private double getDirectionForUserLocationUpdate() { } private void sendUserLocationUpdateEvent(Location location) { - if(location == null){ + if (location == null) { return; } IEvent event = new MapChangeEvent(this, EventTypes.USER_LOCATION_UPDATED, makeLocationChangePayload(location)); @@ -376,37 +366,38 @@ private void updateLocationLayer(@NonNull Style style) { } mLocationComponentManager.update(style); - - if (mFollowUserLocation) { - mLocationComponentManager.setCameraMode(UserTrackingMode.getCameraMode(mUserTrackingMode)); - } mLocationComponentManager.setFollowUserLocation(mFollowUserLocation); if (mFollowUserLocation) { mLocationComponentManager.setCameraMode(UserTrackingMode.getCameraMode(mUserTrackingMode)); mLocationComponentManager.addOnCameraTrackingChangedListener(new OnCameraTrackingChangedListener() { - @Override public void onCameraTrackingChanged(int currentMode) { - int userTrackingMode = UserTrackingMode.NONE; - switch (currentMode) { - case CameraMode.NONE: - userTrackingMode = UserTrackingMode.NONE; - break; - case CameraMode.TRACKING: - userTrackingMode = UserTrackingMode.FOLLOW; - break; - case CameraMode.TRACKING_COMPASS: - userTrackingMode = UserTrackingMode.FollowWithHeading; - break; - case CameraMode.TRACKING_GPS: - userTrackingMode = UserTrackingMode.FollowWithCourse; - break; - default: - userTrackingMode = UserTrackingMode.NONE; - } - updateUserTrackingMode(userTrackingMode); - } - @Override public void onCameraTrackingDismissed() { + @Override + public void onCameraTrackingChanged(int currentMode) { + int userTrackingMode; + + switch (currentMode) { + case CameraMode.NONE: + userTrackingMode = UserTrackingMode.NONE; + break; + case CameraMode.TRACKING: + userTrackingMode = UserTrackingMode.FOLLOW; + break; + case CameraMode.TRACKING_COMPASS: + userTrackingMode = UserTrackingMode.FollowWithHeading; + break; + case CameraMode.TRACKING_GPS: + userTrackingMode = UserTrackingMode.FollowWithCourse; + break; + default: + userTrackingMode = UserTrackingMode.NONE; } + + updateUserTrackingMode(userTrackingMode); + } + + @Override + public void onCameraTrackingDismissed() { + } }); } else { mLocationComponentManager.setCameraMode(CameraMode.NONE); @@ -429,10 +420,7 @@ public void setZoomLevel(double zoomLevel) { } private CameraPosition buildCamera(CameraPosition previousPosition, boolean shouldUpdateTarget) { - CameraPosition.Builder builder = new CameraPosition.Builder(previousPosition) - .bearing(mHeading) - .tilt(mPitch) - .zoom(mZoomLevel); + CameraPosition.Builder builder = new CameraPosition.Builder(previousPosition).bearing(mHeading).tilt(mPitch).zoom(mZoomLevel); if (shouldUpdateTarget) { builder.target(GeoJSONUtils.toLatLng(mCenterCoordinate)); @@ -507,6 +495,7 @@ MapLibreMap getMapboxMap() { /** * Create a payload of the location data per the web api geolocation spec * https://dev.w3.org/geo/api/spec-source.html#position + * * @return */ private WritableMap makeLocationChangePayload(Location location) { diff --git a/android/src/main/java/org/maplibre/reactnative/components/location/LocationComponentManager.java b/android/src/main/java/org/maplibre/reactnative/components/location/LocationComponentManager.java index e7562d898..67b5a8850 100644 --- a/android/src/main/java/org/maplibre/reactnative/components/location/LocationComponentManager.java +++ b/android/src/main/java/org/maplibre/reactnative/components/location/LocationComponentManager.java @@ -46,6 +46,8 @@ public LocationComponentManager(MLRNMapView mlrnMapView, Context context) { private boolean mShowingUserLocation = false; + private OnCameraTrackingChangedListener mOnCameraTrackingChangedListener = null; + public void showUserLocation(boolean showUserLocation) { mShowUserLocation = showUserLocation; stateChanged(); @@ -68,16 +70,21 @@ public void setRenderMode(@RenderMode.Mode int renderMode) { } public void setPreferredFramesPerSecond(int preferredFramesPerSecond) { - if(mLocationComponent == null || preferredFramesPerSecond <= 0) { + if (mLocationComponent == null || preferredFramesPerSecond <= 0) { return; - } + } mLocationComponent.setMaxAnimationFps(preferredFramesPerSecond); } - public void addOnCameraTrackingChangedListener(OnCameraTrackingChangedListener onCameraTrackingChangedListener) { - mLocationComponent.addOnCameraTrackingChangedListener(onCameraTrackingChangedListener); + if (mOnCameraTrackingChangedListener != null) { + mLocationComponent.removeOnCameraTrackingChangedListener(mOnCameraTrackingChangedListener); + } + + mOnCameraTrackingChangedListener = onCameraTrackingChangedListener; + + mLocationComponent.addOnCameraTrackingChangedListener(mOnCameraTrackingChangedListener); } @SuppressLint("MissingPermission") @@ -111,7 +118,7 @@ public void update(@NonNull Style style) { public void update(boolean displayUserLocation, @NonNull Style style) { Integer tintColor = mMapView.getTintColor(); - if (mLocationComponent == null || tintColor != null ) { + if (mLocationComponent == null || tintColor != null) { mLocationComponent = mMap.getLocationComponent(); LocationComponentActivationOptions locationComponentActivationOptions = LocationComponentActivationOptions @@ -148,10 +155,10 @@ LocationComponentOptions options(boolean displayUserLocation) { .accuracyAlpha(0.0f); } else if (tintColor != null) { builder = builder - .enableStaleState(false) - .bearingTintColor(tintColor) - .foregroundTintColor(tintColor) - .accuracyColor(tintColor); + .enableStaleState(false) + .bearingTintColor(tintColor) + .foregroundTintColor(tintColor) + .accuracyColor(tintColor); } return builder.build(); } diff --git a/ios/MLRN/MLRNCamera.m b/ios/MLRN/MLRNCamera.m index 2a6f99922..e5862b5f3 100644 --- a/ios/MLRN/MLRNCamera.m +++ b/ios/MLRN/MLRNCamera.m @@ -179,11 +179,6 @@ - (void)_updateCameraFromTrackingMode return; } - if (_map.userTrackingMode != [self _userTrackingMode]) { - _map.showsUserLocation = [self _userTrackingMode] != MLNUserTrackingModeNone; - _map.userTrackingMode = [self _userTrackingMode]; - } - MLNMapCamera *camera = _map.camera; if (_followPitch != nil && [_followPitch floatValue] >= 0.0) { camera.pitch = [_followPitch floatValue]; @@ -202,8 +197,12 @@ - (void)_updateCameraFromTrackingMode if (_followZoomLevel != nil && [_followZoomLevel doubleValue] >= 0.0) { camera.altitude = [_map altitudeFromZoom:[_followZoomLevel doubleValue]]; } - - [_map setCamera:camera animated:YES]; + + [_map setCamera:camera animated:NO]; + + if (_map.userTrackingMode != [self _userTrackingMode]) { + [_map setUserTrackingMode:[self _userTrackingMode] animated:NO completionHandler:nil]; + } } - (NSUInteger)_userTrackingMode diff --git a/packages/examples/src/Examples.tsx b/packages/examples/src/Examples.tsx index 69594fcee..b32111f53 100644 --- a/packages/examples/src/Examples.tsx +++ b/packages/examples/src/Examples.tsx @@ -117,6 +117,10 @@ const Examples = new ExampleGroup( "Follow User Location Render Mode", MapLibreExamples.FollowUserLocationRenderMode, ), + new ExampleItem( + "User Location for Navigation", + MapLibreExamples.UserLocationForNavigation, + ), new ExampleItem( "User Location Updates", MapLibreExamples.UserLocationUpdate, diff --git a/packages/examples/src/examples/UserLocation/UserLocationForNavigation.tsx b/packages/examples/src/examples/UserLocation/UserLocationForNavigation.tsx new file mode 100755 index 000000000..54b95de07 --- /dev/null +++ b/packages/examples/src/examples/UserLocation/UserLocationForNavigation.tsx @@ -0,0 +1,78 @@ +import { + Camera, + MapView, + SymbolLayer, + UserLocation, + UserLocationRenderMode, + UserTrackingMode, +} from "@maplibre/maplibre-react-native"; +import { useState } from "react"; +import { Button } from "react-native"; + +import maplibreIcon from "../../assets/images/maplibre.png"; +import { OSM_RASTER_STYLE } from "../../constants/OSM_RASTER_STYLE"; +import { sheet } from "../../styles/sheet"; + +export function UserLocationForNavigation() { + const [navigationActive, setNavigationActive] = useState(false); + + return ( + <> +