I am using React native maps for my app. I have restaurants data with latitude and longitude. I have setup user's current location by using expo location(Current location logic will work on real device not Simulator or expo's Snack
). I sorting the restaurant locations based on latitude and longitude
and display my restaurant's location by using Marker
. Based on my User current location around 5 km radius I want to display nearest restaurants in the BottomSheet
. When the user will Zoom out the map it will display more restaurant options and also display in the BottomSheet
. I have used expo Geofence
logic. But the thing I am looking I did not find anywhere in Expo documentation.
I share code in Snack. ps: this will work only ios and android not webView.
This is my map code
import React, { ReactElement, useEffect, useRef, useState } from 'react';
import {
Animated, Button, Dimensions, Image, PermissionsAndroid, StatusBar,
StyleSheet, Text, TouchableOpacity, View
} from 'react-native';
import datas from './components/task.json';
import MapView, { Callout, Circle, Marker, PROVIDER_GOOGLE } from 'react-native-maps';
import * as Location from 'expo-location';
import * as Permissions from 'expo-permissions';
import { LocationGeofencingEventType } from 'expo-location';
import { FAB, Searchbar } from "react-native-paper";
import * as TaskManager from 'expo-task-manager';
import BottomSheet from "react-native-bottomsheet-reanimated";
export default function Map({ navigation }: Props): ReactElement {
const [searchItem, setsearchItem] = useState({
"item": ``
});
const [state, setstate] = useState({
"latitude": 60.1098678,
"longitude": 24.7385084,
"latitudeDelta": 0.9,
"longitudeDelta": 0.0
});
useEffect(() => {
_onMapReady();
}, []);
const _onMapReady = async () => {
const { status } = await Permissions.askAsync(Permissions.LOCATION);
console.log(status);
if (status !== `granted`) {
console.log(`Permisson Denied`);
}
const location = await Location.getCurrentPositionAsync({ "accuracy": Location.Accuracy.High });
setstate({
...state,
"latitude": location.coords.latitude,
"longitude": location.coords.longitude
});
Location.startGeofencingAsync(`LOCATION_GEOFENCE`, [
{
"identifier": `estates logs properties`,
"latitude": state.latitude,
"longitude": state.longitude,
"radius": 2000,
"notifyOnEnter": true,
"notifyOnExit": true
}
]);
};
const nameFilter = datas.data.filter((list) => {
return list?.restaurant?.toLowerCase().includes(searchItem?.item?.toLowerCase());
});
return (
<View style={styles.container}>
<StatusBar hidden={true} />
<MapView
provider={PROVIDER_GOOGLE}
region={state}
showsIndoors={true}
showsMyLocationButton={true}
zoomControlEnabled={true}
zoomEnabled={true}
zoomTapEnabled={true}
showsScale={true}
// showsTraffic={true}
showsBuildings={true}
showsUserLocation={true}
showsCompass={true}
onMapReady={_onMapReady}
style={styles.mapStyle} >
{
nameFilter?.map((i, index) => {
return (
<Marker
key={index}
coordinate={{ "latitude": i.location.lat, "longitude": i.location.lng }}
animation={true}
>
<Callout
style={{ "width": 100, "height": 50 }}>
<View>
<Text>{i.restaurant}</Text>
</View>
</Callout>
</Marker>);
})
}
</MapView>
<Searchbar
placeholder="Search"
style={{
"position": `absolute`,
"top": 20,
"margin": 10
}}
value={searchItem?.item}
onChangeText= {(item) => setsearchItem({ ...searchItem, item })}
icon="menu"
onIconPress={() => {}}
/>
<BottomSheet
bottomSheerColor="#FFFFFF"
initialPosition={`30%`} // 200, 300
snapPoints={[`30%`, `100%`]}
isBackDropDismisByPress={true}
isRoundBorderWithTipHeader={true}
containerStyle={{ "backgroundColor": `#0af` }}
header={
<View>
<Text style={styles.text}>Places Near you</Text>
</View>
}
body={
<View style={styles.body}>
{datas?.data.map((i, index) => <Text key={index}>{i.restaurant}</Text>)}
</View>
}
/>
</View>
);
}
const styles = StyleSheet.create({
"container": {
"flex": 1,
"backgroundColor": `#fff`,
"alignItems": `center`,
"justifyContent": `center`
// position: 'absolute',
// height: Dimensions.get("window").height,
// width: Dimensions.get("window").width
},
"mapStyle": {
// "width": 390,
// "height": 390
"height": Dimensions.get(`window`).height,
"width": Dimensions.get(`window`).width
},
"body": {
"justifyContent": `center`,
"alignItems": `center`
},
"text": {
"fontSize": 20,
"fontWeight": `bold`
}
});
TaskManager.defineTask(`LOCATION_GEOFENCE`, ({ "data": { eventType, region }, error }) => {
console.log(`Region`, region);
if (error) {
// check `error.message` for more details.
console.log(`ERROR: ` + error);
return;
}
if (eventType === Location.GeofencingEventType.Enter) {
alert(`enter in region!`);
console.log(`You've entered region:`, region);
} else if (eventType === Location.GeofencingEventType.Exit) {
console.log(`You've left region:`, region);
}
});
Snack
in the question. – Hurry