I am trying to get the longitude and langtitude but it seems like I can't access it from the default geolocation json object that I get.
I followed this example form the docs and it works great but I only need the long & lat so I am trying to pick it out like this:
const LATITUDE = 19.0760;
const LONGITUDE = 72.8777;
class Map extends Component {
state = {
region: {
latitude: LATITUDE,
longitude: LONGITUDE
},
};
watchID: ?number = null;
componentDidMount() {
navigator.geolocation.getCurrentPosition(
(position) => {
var initialPosition = JSON.stringify(position);
this.setState({
initialRegion: {
latitude: initialPosition.coords.latitude,
longitude: initialPosition.coords.longitude,
}
});
},
(error) => alert(JSON.stringify(error)),
{enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
);
this.watchID = navigator.geolocation.watchPosition((position) => {
var lastPosition = JSON.stringify(position);
this.setState({
lastRegion: {
latitude: lastPosition.coords.latitude,
longitude: lastPosition.coords.longitude,
}
});
});
}
componentWillUnmount() {
navigator.geolocation.clearWatch(this.watchID);
}
render() {
return (
<View>
<Text>
<Text style={styles.title}>Initial position: </Text>
{this.state.initialRegion}
</Text>
<Text>
<Text style={styles.title}>Current position: </Text>
{this.state.lastRegion}
</Text>
</View>
);
}
}
Eventualy I want to do render something like this:
render() {
return (
<MapView
style={ styles.map }
initialRegion={{
latitude: {this.state.lat},
longitude:{this.state.long},
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
/>
);
}
Try this:
import React, { Component } from 'react';
import {
MapView,
StyleSheet,
View,
} from 'react-native';
var Dimensions = require('Dimensions'),
windowSize = Dimensions.get('window'),
Screen = require('Dimensions').get('window'),
NavigationBar = require('react-native-navbar');
var regionText = {
latitude: '0',
longitude: '0',
latitudeDelta: '0',
longitudeDelta: '0',
};
class LocateMap extends Component {
createAnnotation(longitude, latitude) {
return {
longitude,
latitude,
draggable: true,
onDragStateChange: (event) => {
if (event.state === 'starting') {
this.setState({
annotations: [this.createAnnotation(event.longitude, event.latitude)],
});
}
},
};
}
constructor(props) {
super(props);
this.state = {
isFirstLoad: true,
annotations: [],
mapRegion: undefined,
};
}
render() {
if (this.state.isFirstLoad) {
var onRegionChangeComplete = (region) => {
//When the MapView loads for the first time, we can create the annotation at the
//region that was loaded.
this.setState({
isFirstLoad: true,
annotations: [this.createAnnotation(region.longitude, region.latitude)],
});
};
}
const rightButtonConfig = {
title: 'Locate',
tintColor:'#ffffff',
handler: () => {
this.props.data.getMapPosition(this.state.annotations[0].longitude, this.state.annotations[0].latitude);
this.props.navigator.pop();
},
};
return (
<View style={{flex:1}}>
<MapView
style={styles.map}
onRegionChangeComplete={onRegionChangeComplete}
region={this.state.mapRegion}
annotations={this.state.annotations}
zoomEnabled={true}
showsUserLocation={true}
/>
</View>
);
}
};
var styles = StyleSheet.create({
map: {
height: Screen.height,
width: Screen.width
}
});
module.exports= LocateMap;
Related
I am building a ReactNative application for both IOS and Android platforms. My app needs to read data from another device via BLE communication. I am using this package for implementing BLE communication, https://github.com/innoveit/react-native-ble-manager. I am having a problem with receiving characteristic data on IOS even though it is working as expected on the Android platform.
I have added the following to the info.plist file:
Privacy - Bluetooth Always Usage Description: App needs to use Bluetooth to receive data from WaterRower machine
I have a component that scan and list down the BLE devices as follow. It is called, BleDeviceList.js
import React, {
useState,
useEffect,
} from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
NativeModules,
NativeEventEmitter,
Button,
Platform,
PermissionsAndroid,
FlatList,
TouchableHighlight,
} from 'react-native';
import {
Colors,
} from 'react-native/Libraries/NewAppScreen';
import BleManager from 'react-native-ble-manager';
const BleManagerModule = NativeModules.BleManager;
const bleManagerEmitter = new NativeEventEmitter(BleManagerModule);
const BleDeviceList = (props) => {
const [isScanning, setIsScanning] = useState(false);
const peripherals = new Map();
const [list, setList] = useState([]);
const [ connectedDevices, setConnectedDevices ] = useState([ ]);
const [ permissionsAllowed, setPermissionsAllowed ] = useState(false)
const startScan = () => {
if (!isScanning) {
BleManager.scan([], 3, true).then((results) => {
console.log('Scanning...');
setIsScanning(true);
}).catch(err => {
console.error(err);
});
}
}
const handleStopScan = () => {
console.log('Scan is stopped');
setIsScanning(false);
}
const handleDisconnectedPeripheral = (data) => {
let peripheral = peripherals.get(data.peripheral);
if (peripheral) {
peripheral.connected = false;
peripherals.set(peripheral.id, peripheral);
setList(Array.from(peripherals.values()));
}
console.log('Disconnected from ' + data.peripheral);
}
const handleUpdateValueForCharacteristic = (data) => {
console.log('Received data from ' + data.peripheral + ' characteristic ' + data.characteristic, data.value);
}
const retrieveConnected = () => {
BleManager.getConnectedPeripherals([]).then((results) => {
if (results.length == 0) {
console.log('No connected peripherals')
}
console.log(results);
for (var i = 0; i < results.length; i++) {
var peripheral = results[i];
peripheral.connected = true;
peripherals.set(peripheral.id, peripheral);
setList(Array.from(peripherals.values()));
}
});
}
const handleDiscoverPeripheral = (peripheral) => {
console.log('Got ble peripheral', peripheral);
if (!peripheral.name) {
peripheral.name = 'NO NAME';
}
peripherals.set(peripheral.id, peripheral);
setList(Array.from(peripherals.values()));
}
const isConnected = (peripheral) => {
return connectedDevices.filter(cd => cd.id == peripheral.id).length > 0;
}
const toggleConnectPeripheral = (peripheral) => {
if (peripheral){
if (isConnected(peripheral)){
BleManager.disconnect(peripheral.id);
setConnectedDevices(connectedDevices.filter(cd => cd.id != peripheral.id))
}else{
BleManager.connect(peripheral.id).then(() => {
let tempConnnectedDevices = [ ...connectedDevices ]
tempConnnectedDevices.push(peripheral);
setConnectedDevices(tempConnnectedDevices);
props.navigation.push('BleRowingSession', { peripheral: peripheral });
let p = peripherals.get(peripheral.id);
if (p) {
p.connected = true;
peripherals.set(peripheral.id, p);
setList(Array.from(peripherals.values()));
props.navigation.push('BleDeviceServiceList', { peripheral: peripheral });
}
console.log('Connected to ' + peripheral.id);
}).catch((error) => {
console.log('Connection error', error);
});
}
}
}
useEffect(() => {
BleManager.start({showAlert: false});
bleManagerEmitter.addListener('BleManagerDiscoverPeripheral', handleDiscoverPeripheral);
bleManagerEmitter.addListener('BleManagerStopScan', handleStopScan );
bleManagerEmitter.addListener('BleManagerDisconnectPeripheral', handleDisconnectedPeripheral );
bleManagerEmitter.addListener('BleManagerDidUpdateValueForCharacteristic', handleUpdateValueForCharacteristic );
if (Platform.OS === 'android' && Platform.Version >= 23) {
PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION).then((result) => {
if (result) {
console.log("Permission is OK");
setPermissionsAllowed(true);
} else {
PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION).then((result) => {
if (result) {
console.log("User accept");
setPermissionsAllowed(true);
} else {
console.log("User refuse");
setPermissionsAllowed(false);
}
});
}
});
} else {
setPermissionsAllowed(true)
}
return (() => {
console.log('unmount');
bleManagerEmitter.removeListener('BleManagerDiscoverPeripheral', handleDiscoverPeripheral);
bleManagerEmitter.removeListener('BleManagerStopScan', handleStopScan );
bleManagerEmitter.removeListener('BleManagerDisconnectPeripheral', handleDisconnectedPeripheral );
bleManagerEmitter.removeListener('BleManagerDidUpdateValueForCharacteristic', handleUpdateValueForCharacteristic );
})
}, []);
const renderConnectButton = (item) => {
if (isConnected(item)) {
return null
}
return (
<Button
title="Connect"
onPress={() => {
toggleConnectPeripheral(item)
}}
/>
)
}
const renderDisconnectButton = (item) => {
if (! isConnected(item)) {
return null
}
return (
<Button
title="Disconnect"
onPress={() => {
toggleConnectPeripheral(item)
}}
/>
)
}
const renderItem = (item) => {
const color = item.connected ? 'green' : '#fff';
return (
<TouchableHighlight>
<View style={[styles.row, {backgroundColor: color}]}>
<Text style={{fontSize: 12, textAlign: 'center', color: '#333333', padding: 10}}>{item.name}</Text>
<Text style={{fontSize: 10, textAlign: 'center', color: '#333333', padding: 2}}>RSSI: {item.rssi}</Text>
<Text style={{fontSize: 8, textAlign: 'center', color: '#333333', padding: 2, paddingBottom: 20}}>{item.id}</Text>
{renderConnectButton(item)}
{renderDisconnectButton(item)}
</View>
</TouchableHighlight>
);
}
const renderContent = () => {
if (! permissionsAllowed) {
return <Text>Bluetooth and locations permissions are required.</Text>
}
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={styles.scrollView}>
{global.HermesInternal == null ? null : (
<View style={styles.engine}>
<Text style={styles.footer}>Engine: Hermes</Text>
</View>
)}
<View style={styles.body}>
<View style={{margin: 10}}>
<Button
title={'Scan Bluetooth (' + (isScanning ? 'on' : 'off') + ')'}
onPress={() => startScan() }
/>
</View>
<View style={{margin: 10}}>
<Button title="Retrieve connected peripherals" onPress={() => retrieveConnected() } />
</View>
{(list.length == 0) &&
<View style={{flex:1, margin: 20}}>
<Text style={{textAlign: 'center'}}>No peripherals</Text>
</View>
}
</View>
</ScrollView>
<FlatList
data={list}
renderItem={({ item }) => renderItem(item) }
keyExtractor={item => item.id}
/>
</SafeAreaView>
</>
)
}
return (
renderContent()
);
};
const styles = StyleSheet.create({
scrollView: {
backgroundColor: Colors.lighter,
},
engine: {
position: 'absolute',
right: 0,
},
body: {
backgroundColor: Colors.white,
},
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
color: Colors.black,
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
color: Colors.dark,
},
highlight: {
fontWeight: '700',
},
footer: {
color: Colors.dark,
fontSize: 12,
fontWeight: '600',
padding: 4,
paddingRight: 12,
textAlign: 'right',
},
});
export default BleDeviceList;
As you can see in the code, when the Connect button is clicked, it will redirect the user to another component that reads data from another device. The following is the BleRowingSession.js that reads the data from another device.
import React, { useEffect, useState } from 'react';
import { Text, View, StyleSheet, NativeModules, NativeEventEmitter, ScrollView } from 'react-native';
import BleManager from 'react-native-ble-manager';
const BleManagerModule = NativeModules.BleManager;
const bleManagerEmitter = new NativeEventEmitter(BleManagerModule);
const serviceId = "00001826-0000-1000-8000-00805F9B34FB";
const characteristicId = "00002AD1-0000-1000-8000-00805F9B34FB";
let readDataCache = "";
const BleRowingSession = (props) => {
let peripheral = props.route.params.peripheral;
const [ readData, setReadData ] = useState("");
const setUpBleNotification = () => {
BleManager.retrieveServices(peripheral.id).then((peripheralData) => {
console.log('Retrieved peripheral services', peripheralData);
setTimeout(() => {
BleManager.startNotification(peripheral.id, serviceId, characteristicId).then(() => {
console.log('Started notification on ' + peripheral.id);
bleManagerEmitter.addListener('BleManagerDidUpdateValueForCharacteristic', (data) => {
readDataCache = readDataCache + "\n" + data.value.toString()
setReadData(readDataCache);
});
setTimeout(() => {
}, 500);
}).catch((error) => {
console.log('Notification error', error);
});
}, 500)
});
}
useEffect(() => {
setUpBleNotification()
}, [ ])
return (
<View style={styles.container}>
<ScrollView>
<Text>Ble Rowing Session</Text>
<Text>{readData}</Text>
</ScrollView>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center"
}
})
export default BleRowingSession;
For now, the service id and characteristic id are hardcoded. Of course, I had to choose the right device on the first page that displays the list of BLE devices.
When I run the code, it is working as expected on the Android device, it is receiving the characteristic value. When I run the code on the actual IOS device, it is not receiving any data. But it can scan the devices and connect to them. What is wrong with my code and how can I fix it?
I'm having an issue with rendering google map markers from a state array. Only the last rendered marker is shown although all of the markers are listed in react components
I am using google-maps-react to display a location with many markers representing bookclubs. I fetch the addresses for my markers from a rails API, loop them into a geocoder and set the state within the loop. Each object within the state has the bookclubs lat, lng and data.
I receive the center maps location via form. the data in the form goes through the geocoder and is set to state for the map.
When I add markers using data from state.markers only the last coded marker will show up. This applies when I loop through state.markers or not.
import React, { Component } from "react";
import { Map, InfoWindow, Marker, GoogleApiWrapper } from "google-maps-react";
class GoogleMaps extends Component {
constructor(props) {
super(props);
this.state = {
markers: [],
lat: null,
lng: null,
showingInfoWindow: false,
activeMarker: {},
selectedPlace: {}
};
}
componentDidMount() {
fetch("RAILS API ROUTE", {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + sessionStorage.JWT
}
})
.then(e => e.json())
.then(data => {
let bookClubs = data.book_clubs;
console.log("let", bookClubs);
bookClubs.forEach(club => {
const googleMapsClient = require("#google/maps").createClient({
key: "API KEY",
Promise: Promise
});
googleMapsClient
.geocode({
address: `${(club.address.address_line1,
club.address.address_line2,
club.address.city)}`
})
.asPromise()
.then(response => {
console.log("response!!!!!!!!!!!!!", response.json.results);
let info = {
lat: response.json.results[0].geometry.location.lat,
lng: response.json.results[0].geometry.location.lng,
bookClub: club
};
let dataCopy = this.state.markers
dataCopy.push(info);
this.setState(
{
markers: dataCopy
},
() => {
console.log("State::::", this.state.markers);
}
);
});
});
})
.catch(error => console.error("Error:", error));
}
onMarkerClick = (props, marker, e) =>
this.setState({
selectedPlace: props,
activeMarker: marker,
showingInfoWindow: true
});
onMapClicked = props => {
if (this.state.showingInfoWindow) {
this.setState({
showingInfoWindow: false,
activeMarker: null
});
}
};
render() {
return (
<div
style={{ display: "flex", flexDirection: "flexEnd", flexWrap: "wrap" }}
>
{this.state.lat != null && (
<Map
onClick={this.onMapClick}
google={this.props.google}
initialCenter={{
lng: this.state.lng,
lat: this.state.lat
}}
center={{
lng: this.state.lng,
lat: this.state.lat
}}
containerStyle={{
width: "100%",
height: "250px",
position: "relative"
}}
style={{
height: "35vh",
width: "35vh",
display: "flex",
justifyContent: "flexEnd"
}}
zoom={14}
>
{this.state.markers.map((e, i) => (
<Marker
key={i}
onClick={this.onMarkerClick}
position={{ lat: e.lat, lng: e.lng }}
title={`${e.bookClub.address.address_line1} ${e.bookClub.address.address_line2}`}
name={e.bookClub.address.city}
/>
))}
<InfoWindow
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}
>
<div>
<h1>{this.state.selectedPlace.name}</h1>
</div>
</InfoWindow>
</Map>
)
}
</div>
);
}
}
export default GoogleApiWrapper({
apiKey: "API KEY"
})(GoogleMaps);
The problem was that I was adding commas while inserting data into my geocoder.
googleMapsClient
.geocode({
address: `${(club.address.address_line1,
club.address.address_line2,
club.address.city)}
I removed the commas and made the code like below, which solved my problem.
googleMapsClient
.geocode({
address: `${club.address.address_line1} ${club.address.address_line2} ${club.address.city} `
})
The reason only the last marker showed is that the geocoder gave all the markers the same lat and lng when I had commas. This caused all of them to cover each other in the same location while the last rendered marker was left on top.
I want to add tabs at the bottom of my home screen but I don't manage how to do it.
I want two tabs like "Map" (for my homepage) and "Settings". I don't know how to create that, I tried to add some codes inside but it's not working. Do you have ideas of what I'm doing wrong?
Do I need to add these codes inside ?
class HomeScreen extends React.Component {
render() {
return (
class SettingsScreen extends React.Component {
render() {
return (
I also tried to add this code at the bottom:
const TabNavigator = createBottomTabNavigator({
MAP: { screen: HomeScreen },
SETTINGS: { screen: SettingsScreen },
});
export default createAppContainer(TabNavigator);
Here is my code:
import React, { Component } from 'react';
import { StyleSheet, Text, View, Animated, Image, Dimensions } from "react-native";
import { Components, MapView } from 'expo';
const Images = [
{ uri: "https://images.unsplash.com/photo-1555706655-6dd427c11735?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80" },
{ uri: "https://images.unsplash.com/photo-1555706741-8f39aa887cf7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80" },
{ uri: "https://images.unsplash.com/photo-1555706741-fade7dd756a9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80" },
{ uri: "https://images.unsplash.com/photo-1555706742-67a1170e528d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80" }
]
const { width, height } = Dimensions.get("window");
const CARD_HEIGHT = height / 5;
const CARD_WIDTH = CARD_HEIGHT - 50;
export default class screens extends Component {
state = {
markers: [
{
coordinate: {
latitude: 41.414494,
longitude: 2.152695,
},
title: "Parc Güell",
description: "One of the best view in Barcelona. ",
image: Images[0],
},
{
coordinate: {
latitude: 41.403706,
longitude: 2.173504,
},
title: "Sagrada Familia",
description: "This is the second best place in Portland",
image: Images[1],
},
{
coordinate: {
latitude: 41.395382,
longitude: 2.161961,
},
title: "Casa Milà",
description: "This is the third best place in Portland",
image: Images[2],
},
{
coordinate: {
latitude: 41.381905,
longitude: 2.178185,
},
title: "Gothic Quarter",
description: "This is the fourth best place in Portland",
image: Images[3],
},
],
region: {
latitude: 41.390200,
longitude: 2.154007,
latitudeDelta: 0.04864195044303443,
longitudeDelta: 0.040142817690068,
},
};
componentWillMount() {
this.index = 0;
this.animation = new Animated.Value(0);
}
componentDidMount() {
// We should detect when scrolling has stopped then animate
// We should just debounce the event listener here
this.animation.addListener(({ value }) => {
let index = Math.floor(value / CARD_WIDTH + 0.3); // animate 30% away from landing on the next item
if (index >= this.state.markers.length) {
index = this.state.markers.length - 1;
}
if (index <= 0) {
index = 0;
}
clearTimeout(this.regionTimeout);
this.regionTimeout = setTimeout(() => {
if (this.index !== index) {
this.index = index;
const { coordinate } = this.state.markers[index];
this.map.animateToRegion(
{
...coordinate,
latitudeDelta: this.state.region.latitudeDelta,
longitudeDelta: this.state.region.longitudeDelta,
},
350
);
}
}, 10);
});
}
render() {
const interpolations = this.state.markers.map((marker, index) => {
const inputRange = [
(index - 1) * CARD_WIDTH,
index * CARD_WIDTH,
((index + 1) * CARD_WIDTH),
];
const scale = this.animation.interpolate({
inputRange,
outputRange: [1, 2.5, 1],
extrapolate: "clamp",
});
const opacity = this.animation.interpolate({
inputRange,
outputRange: [0.35, 1, 0.35],
extrapolate: "clamp",
});
return { scale, opacity };
});
return (
<View style={styles.container}>
<MapView
ref={map => this.map = map}
initialRegion={this.state.region}
style={styles.container}
>
{this.state.markers.map((marker, index) => {
const scaleStyle = {
transform: [
{
scale: interpolations[index].scale,
},
],
};
const opacityStyle = {
opacity: interpolations[index].opacity,
};
return (
<MapView.Marker key={index} coordinate={marker.coordinate}>
<Animated.View style={[styles.markerWrap, opacityStyle]}>
<Animated.View style={[styles.ring, scaleStyle]} />
<View style={styles.marker} />
</Animated.View>
</MapView.Marker>
);
})}
</MapView>
<Animated.ScrollView
horizontal
scrollEventThrottle={1}
showsHorizontalScrollIndicator={false}
snapToInterval={CARD_WIDTH}
onScroll={Animated.event(
[
{
nativeEvent: {
contentOffset: {
x: this.animation,
},
},
},
],
{ useNativeDriver: true }
)}
style={styles.scrollView}
contentContainerStyle={styles.endPadding}
>
{this.state.markers.map((marker, index) => (
<View style={styles.card} key={index}>
<Image
source={marker.image}
style={styles.cardImage}
resizeMode="cover"
/>
<View style={styles.textContent}>
<Text numberOfLines={1} style={styles.cardtitle}>{marker.title}</Text>
<Text numberOfLines={1} style={styles.cardDescription}>
{marker.description}
</Text>
</View>
</View>
))}
</Animated.ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
scrollView: {
position: "absolute",
bottom: 30,
left: 0,
right: 0,
paddingVertical: 10,
},
endPadding: {
paddingRight: width - CARD_WIDTH,
},
card: {
padding: 10,
elevation: 2,
backgroundColor: "#FFF",
marginHorizontal: 10,
shadowColor: "#000",
shadowRadius: 5,
shadowOpacity: 0.3,
shadowOffset: { x: 2, y: -2 },
height: CARD_HEIGHT,
width: CARD_WIDTH,
overflow: "hidden",
},
cardImage: {
flex: 3,
width: "100%",
height: "100%",
alignSelf: "center",
},
textContent: {
flex: 1,
},
cardtitle: {
fontSize: 12,
marginTop: 5,
fontWeight: "bold",
},
cardDescription: {
fontSize: 12,
color: "#444",
},
markerWrap: {
alignItems: "center",
justifyContent: "center",
},
marker: {
width: 8,
height: 8,
borderRadius: 4,
backgroundColor: "rgba(130,4,150, 0.9)",
},
ring: {
width: 24,
height: 24,
borderRadius: 12,
backgroundColor: "rgba(130,4,150, 0.3)",
position: "absolute",
borderWidth: 1,
borderColor: "rgba(130,4,150, 0.5)",
},
});
create a new file for tab navigation and add the following code:
(I imported your map component as screens)
import React from 'react';
import { Platform } from 'react-native';
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';
import TabBarIcon from '../components/TabBarIcon';
import screens from '../screens/HomeScreen';
import SettingsScreen from '../screens/SettingsScreen';
const HomeStack = createStackNavigator({
Home: screens,
});
HomeStack.navigationOptions = {
tabBarLabel: 'Home',
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name={
Platform.OS === 'ios'
? `ios-information-circle${focused ? '' : '-outline'}`
: 'md-information-circle'
}
/>
),
};
const SettingsStack = createStackNavigator({
Settings: SettingsScreen,
});
SettingsStack.navigationOptions = {
tabBarLabel: 'Settings',
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name={Platform.OS === 'ios' ? 'ios-options' : 'md-options'}
/>
),
};
export default createBottomTabNavigator({
HomeStack,
SettingsStack,
});
I'm building a react native app using the react-native-maps dependency but am unable to navigate to other screens using react-navigator onPress from within the MapView.
I would like to pass the { communityId: ${community._id} } object to view the unique community screen.
code:
import React, { Component } from 'react';
import { View, Image, StyleSheet, Vibration, TouchableOpacity, Text } from 'react-native';
import MapView, { Callout } from 'react-native-maps';
import { Marker } from 'react-native-maps';
class LogoTitle extends React.Component {
render() {
return (
<Image
source={require("./logo.png")}
style={{ width: 60, height: 30 }}
/>
);
}
}
class MapScreen extends Component {
constructor(props) {
super(props);
this.state = {
latitude: null,
longitude: null,
error: null,
communities: ""
};
}
componentDidMount() {
fetch("http://localhost:4000/community")
.then(res => res.json())
.then(res => {
this.setState({ communities: res });
});
Vibration.vibrate();
navigator.geolocation.getCurrentPosition(
(position) => {
this.setState({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
error: null,
});
},
(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 },
);
}
static navigationOptions = {
headerTitle: <LogoTitle />
};
navigateToView(viewName, { param: value }) {
console.log(viewName);
const { navigate } = this.props.navigation;
navigate(viewName, { param: value });
}
render() {
const LatLng = {
latitude: this.state.latitude,
longitude: this.state.longitude
}
let commcoords;
this.state.communities &&
(commcoords = this.state.communities.map((community, id) => {
let commlatlong;
commlatlong = {
latitude: community.location.lat,
longitude: community.location.long
};
return (
<Marker
key={id}
coordinate={commlatlong}
title={community.name}>
<Callout>
<TouchableOpacity
onPress={() => this.navigateToView("Community", { communityId: `${community._id}` })}
style={styles.communityButton}>
<Text style={styles.communityButtonText}>{community.name}</Text>
<Text style={styles.descButtonText}>{community.description}</Text>
</TouchableOpacity>
</Callout>
</Marker>
)
}))
return (
<View style={styles.container}>
{this.state.latitude &&
<MapView
style={styles.map}
initialRegion={{
latitude: this.state.latitude,
longitude: this.state.longitude,
latitudeDelta: 0.1011,
longitudeDelta: 0.1011,
}}>
<Marker
coordinate={LatLng}
title={`Latitude: ${this.state.latitude}`}
description={`Longitude: ${this.state.longitude}`}
pinColor='#000000'>
</Marker>
{commcoords}
</MapView>}
</View>
);
}
}
I have already attempted:
1) Using the normal navigation method.
onPress={() => this.props.navigation.navigate("Community", { communityId: `${community._id}` })}
2) Using alternate touch methods, buttons, touchable highlights, etc.
3) Attempted to console.log the triggered touch method using the remote debugger. The console.log was never triggered in the console.
navigateToView(viewName, { param: value }) {
console.log(viewName);
const { navigate } = this.props.navigation;
navigate(viewName, { param: value });
}
4) Researched and attempted solutions to no avail from the following stackoverflow links:
React Native - How to use React Navigation with React Native Maps?
React native maps click pin to take you to another screen
I would like to resolve this maps navigation issue to increase functionality in this native app. If there is an alternative method, I am open to any and all suggestions. Thank you.
I figured out how to trigger an the onpress event by using onCalloutPress in the Marker:
<Marker
key={id}
coordinate={commlatlong}
title={community.name}
onCalloutPress={() => this.props.navigation.navigate("Community", { communityId: `${community._id}` })}>
<Callout>
<TouchableOpacity
style={styles.communityButton}>
<Text style={styles.communityButtonText}>{community.name}</Text>
<Text style={styles.descButtonText}>{community.description}</Text>
</TouchableOpacity>
</Callout>
</Marker>
I am now able to navigate to show screens from the map. Thanks to this post:
Marker click event on react native maps not working in react ios
Additional source:
onCalloutPress Callback that is called when a callout is tapped by the user.
https://github.com/react-native-community/react-native-maps/blob/master/docs/mapview.md
I am running this basic react native code for fetching latitude and longitude value on both android device and emulator but nowhere is the current lat/long value is being returned.
When run on emulator some value is being returned but its not the correct lat/long value, whereas on device value isn't even being return.Here is the code
import React, { Component } from 'react'
import { View, Text, Switch, StyleSheet, Button} from 'react-native'
import { createStackNavigator } from 'react-navigation';
class HomeScreen extends Component {
render() {
return (
<View style = {styles.container}>
<Button
title="Add New Outlet"
onPress={() => this.props.navigation.navigate('Details')}
/>
</View>
)
}
}
class DetailsScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
latitude: null,
longitude: null,
error: null,
};
}
componentDidMount() {
navigator.geolocation.getCurrentPosition(
(position) => {
this.setState({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
error: null,
});
},
(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 },
);
}
render(){
return(
<View style = {styles.container}>
<Text style = {styles.boldText}>
Latitude:
</Text>
<Text>
{this.state.latitude}
</Text>
<Text style = {styles.boldText}>
Longitude:
</Text>
<Text>
{this.state.longitude}
</Text>
</View>
)
}
}
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home',
}
);
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
const styles = StyleSheet.create ({
container: {
flex: 1,
alignItems: 'center',
marginTop: 50
},
boldText: {
fontSize: 30,
color: 'red',
}
})
Please suggest any better alternatives..
For some reason navigator.geolocation is not working stable on Android devices, I changed getCurrentPosition to watchPosition and not used the third(geo_options) parameter. It worked for me.
componentDidMount() {
this.state.watchId = navigator.geolocation.watchPosition(
(position) => console.log(position),
(error) => console.log(error),
);
}
Also, you must clear watch and stop position observing when component unmounts.
componentWillUnmount() {
navigator.geolocation.clearWatch(this.state.watchId);
navigator.geolocation.stopObserving();
}
Fisrt, check android permissions:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Next:
componentDidMount() {
if (Platform.OS === "android") {
PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
).then(granted => {
if (granted) this._getCurrentLocation();
});
} else {
this._getCurrentLocation();
}
}
Then:
_getCurrentLocation = () => {
navigator.geolocation.getCurrentPosition(
(position) => {
this.setState({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
error: null,
});
},
(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 },
);
}