Implement camera controls and expose MapHandle API in MapView

This commit is contained in:
2026-01-30 23:00:14 +05:30
parent 8710bc7a7f
commit 5b04cc9a58
4 changed files with 113 additions and 6 deletions

View File

@@ -29,5 +29,26 @@ export default function App() {
}
```
## Camera Controls 🔧
This package exposes a small imperative `MapHandle` API via `ref` on `MapView`. Use it to animate the camera or fit bounds.
Example:
```ts
const mapRef = useRef<MapHandle | null>(null);
mapRef.current?.flyTo({ latitude: 37.78825, longitude: -122.4324 });
mapRef.current?.fitBounds({ latitude: 37.809, longitude: -122.410 }, { latitude: 37.779, longitude: -122.450 });
```
Available methods:
- `animateToRegion(region, duration?)` — animate to a region.
- `animateCamera(camera, options?)` — animate using camera properties.
- `flyTo(coordinate, duration?)` — quick helper that animates to a small region around `coordinate`.
- `fitBounds(northEast, southWest, options?)` — fit the two coordinates with optional `edgePadding`.
---
## Notes
- This package delegates to `react-native-maps` for platform implementations. Follow `react-native-maps` docs for iOS/Android setup (Google Maps API key, pods, manifest permissions).

View File

@@ -1,10 +1,78 @@
import React from 'react';
import RNMapView, { MapViewProps as RNMapViewProps } from 'react-native-maps';
import React, { forwardRef, useImperativeHandle, useRef } from 'react';
import RNMapView, { MapViewProps as RNMapViewProps, Camera, Region, LatLng } from 'react-native-maps';
export type MapProps = RNMapViewProps;
const MapView: React.FC<MapProps> = (props) => {
return <RNMapView {...props}>{props.children}</RNMapView>;
export type MapHandle = {
animateToRegion: (region: Region, duration?: number) => void;
animateCamera: (camera: Partial<Camera>, options?: { duration?: number }) => void;
flyTo: (coordinate: LatLng, duration?: number) => void;
fitBounds: (
northEast: LatLng,
southWest: LatLng,
options?: { edgePadding?: { top: number; left: number; bottom: number; right: number }; animated?: boolean }
) => void;
getCamera?: () => Promise<Camera | undefined>;
};
const MapView = forwardRef<MapHandle, MapProps>((props, ref) => {
const mapRef = useRef<RNMapView | null>(null);
useImperativeHandle(
ref,
() => ({
animateToRegion(region: Region, duration = 500) {
if (mapRef.current?.animateToRegion) {
mapRef.current.animateToRegion(region, duration);
}
},
animateCamera(camera: Partial<Camera>, options) {
if (mapRef.current?.animateCamera) {
mapRef.current.animateCamera(camera, options);
}
},
flyTo(coordinate: LatLng, duration = 800) {
if (mapRef.current?.animateToRegion) {
const region: Region = {
latitude: coordinate.latitude,
longitude: coordinate.longitude,
latitudeDelta: 0.01,
longitudeDelta: 0.01,
};
mapRef.current.animateToRegion(region, duration);
}
},
fitBounds(
northEast: LatLng,
southWest: LatLng,
options = { edgePadding: { top: 20, left: 20, bottom: 20, right: 20 }, animated: true }
) {
if (mapRef.current?.fitToCoordinates) {
mapRef.current.fitToCoordinates([northEast, southWest], {
edgePadding: options.edgePadding,
animated: options.animated,
});
}
},
async getCamera() {
if (mapRef.current?.getCamera) {
try {
return await mapRef.current.getCamera();
} catch {
return undefined;
}
}
return undefined;
},
}),
[]
);
return (
<RNMapView ref={mapRef} {...props}>
{props.children}
</RNMapView>
);
});
export default MapView;

View File

@@ -1,2 +1,3 @@
export { default as MapView } from './MapView';
export type { MapHandle } from './MapView';
export { Marker, Polyline, PROVIDER_GOOGLE } from 'react-native-maps';