AplicaĆ§Ć£o Front-end Mobile desenvolvida em React Native para clone do app Uber com integraĆ§Ć£o com a API Google Maps. App Ć© voltado para transporte privado urbano, permite a interaĆ§Ć£o do usuĆ”rio entre seu local de origem e destino.
- Expo
- Components
- react-native-maps
- Google Maps Platform API
- Platform
- react-native-google-places-autocomplete
- react-native-google-maps-directions
- Marker
- react-native-geocoding
- States
- PixelRatio
- styled-components
- npm install
- npm run start / npm start
- DĆŖ um fork nesse repositĆ³rio
- Crie a sua branch com a feature
- git checkout -b my-feature
- Commit a sua contribuiĆ§Ć£o
- git commit -m 'feat: My feature'
- Push a sua branch
- git push origin my-feature
import React, { Component, Fragment } from 'react';
import { View, Image } from 'react-native';
//import { MapView } from 'expo';
import MapView, { Marker } from 'react-native-maps';
import Geocoder from 'react-native-geocoding';
import { getPixelSize } from '../../utils';
import Search from '../Search';
import Directions from '../Directions';
import Details from '../Details';
import markerImage from '../../assets/marker.png';
import backImage from '../../assets/back.png';
import
{
Back,
LocationBox,
LocationText,
LocationTimeBox,
LocationTimeText,
LocationTimeTextSmall
} from './styles';
Geocoder.init(" ");
export default class Map extends Component {
state = {
region: null,
destination: null,
duration: null,
location: null
};
async componentDidMount() {
// PosiĆ§Ć£o atual do usuĆ”rio
navigator.geolocation.getCurrentPosition(
// Coordenadas da localizaĆ§Ć£o do usuĆ”rio
async ({ coords: { latitude, longitude } }) => {
const response = await Geocoder.from({ latitude, longitude });
const address = response.results[0].formatted_address;
// endereƧo mĆnimo (atĆ© a vĆrgula)
const location = address.substring(0, address.indexOf(","));
this.setState({
location,
region: {
latitude,
longitude,
latitudeDelta: 0.0143,
longitudeDelta: 0.0134
}
});
}, //sucesso
() => {}, //erro
{
// Tentar buscar conexĆ£o
timeout: 2000,
// LocalizaĆ§Ć£o Gps
enableHighAccuracy: true,
// Intervalo busca
maximumAge: 1000
}
);
}
handleLocationSelected = (data, { geometry }) => {
const {
location: {
lat: latitude,
lng: longitude }
} = geometry;
this.setState({
destination: {
latitude,
longitude,
title: data.structured_formatting.main_text
}
});
};
handleBack = () => {
this.setState({ destination: null });
};
render() {
const { region, destination, duration, location } = this.state;
return (
<View style={{ flex: 1 }}>
<MapView
style={{ flex: 1 }}
region={ region }
showsUserLocation
loadingEnabled
// instĆ¢ncia mapView
ref={el => (this.mapView = el)}
>
{ destination && (
<Fragment>
<Directions
origin={ region }
destination={ destination }
onReady={ result => {
this.setState({ duration: Math.floor(result.duration) });
//ref mapView
this.mapView.fitToCoordinates(result.coordinates, {
edgePadding: {
right: getPixelSize(50),
left: getPixelSize(50),
top: getPixelSize(50),
bottom: getPixelSize(350)
}
});
}}
/>
{/* Marcador destino */}
<Marker
/*
* Local do marcador
* state -- destination
*/
coordinate={ destination }
// ancorar marcador no centro(x: 0, y: 0) da imagem quadrada
anchor={{ x: 0, y: 0 }}
// ref img
image={ markerImage }
>
<LocationBox>
{/*
* Label destino
* state -- title
*/}
<LocationText>{ destination.title }</LocationText>
</LocationBox>
</Marker>
{/**
* Marcador origem
* state -- region, duration, location
*/}
<Marker coordinate={ region } anchor={{ x: 0, y: 0 }}>
<LocationBox>
<LocationTimeBox>
{/* label duraĆ§Ć£o */}
<LocationTimeText>{ duration }</LocationTimeText>
<LocationTimeTextSmall>MIN</LocationTimeTextSmall>
</LocationTimeBox>
{/* label origem */}
<LocationText>{ location }</LocationText>
</LocationBox>
</Marker>
</Fragment>
)}
</MapView>
{/* se selecionar voltar */}
{ destination ? (
<Fragment>
<Back onPress={ this.handleBack }>
<Image source={ backImage } />
</Back>
<Details />
</Fragment>
// senĆ£o..
) : (
<Search onLocationSelected={ this.handleLocationSelected } />
)}
</View>
);
}
};
import React, { Component } from "react";
import { Platform } from "react-native";
import { GooglePlacesAutocomplete }
from "react-native-google-places-autocomplete";
export default class Search extends Component {
state = {
searchFocused: false
};
render() {
const { searchFocused } = this.state;
const { onLocationSelected } = this.props;
return (
<GooglePlacesAutocomplete
placeholder="Para onde?"
placeholderTextColor="#333"
onPress={onLocationSelected}
query={{
key: " ",
language: "pt"
}}
textInputProps={{
// Com foco na barra search
onFocus: () => {
this.setState({ searchFocused: true });
},
// Sem foco na barra search
onBlur: () => {
this.setState({ searchFocused: false });
},
autoCapitalize: "none",
autoCorrect: false
}}
listViewDisplayed={searchFocused}
// Trazer detalhes --> latit, longit, tempo percurso...
fetchDetails
enablePoweredByContainer={false}
styles={{
container: {
position: "absolute",
top: Platform.select({ ios: 60, android: 40 }),
width: "100%"
},
textInputContainer: {
flex: 1,
backgroundColor: "transparent",
height: 54,
marginHorizontal: 20,
borderTopWidth: 0,
borderBottomWidth: 0
},
textInput: {
height: 54,
margin: 0,
borderRadius: 0,
paddingTop: 0,
paddingBottom: 0,
paddingLeft: 20,
paddingRight: 20,
marginTop: 0,
marginLeft: 0,
marginRight: 0,
// sombra android
elevation: 5,
// sombra ios
shadowColor: "#000",
shadowOpacity: 0.1,
shadowOffset: { x: 0, y: 0 },
shadowRadius: 15,
borderWidth: 1,
borderColor: "#DDD",
fontSize: 18
},
listView: {
borderWidth: 1,
borderColor: "#DDD",
backgroundColor: "#FFF",
marginHorizontal: 20,
elevation: 5,
shadowColor: "#000",
shadowOpacity: 0.1,
shadowOffset: { x: 0, y: 0 },
shadowRadius: 15,
marginTop: 10
},
description: {
fontSize: 16
},
row: {
padding: 20,
height: 58
}
}}
/>
);
}
};
import React from 'react';
import MapViewDirections from 'react-native-maps-directions';
//props
const Directions = ({ destination, origin, onReady }) => (
<MapViewDirections
destination={destination}
origin={origin}
onReady={onReady}
apikey=" "
strokeWidth={3}
strokeColor="#222"
/>
);
export default Directions;
import React, { Component } from 'react';
import
{
Container,
TypeTitle,
TypeDescription,
TypeImage,
RequestButton,
RequestButtonText
} from './styles';
import uberx from '../../assets/uberx.png';
export default class Details extends Component {
render() {
return (
<Container>
<TypeTitle>Popular</TypeTitle>
<TypeDescription>Viagens baratas para o dia a dia</TypeDescription>
<TypeImage source={uberx} />
<TypeTitle>UperX</TypeTitle>
<TypeDescription>R$14,00</TypeDescription>
<RequestButton onPress={() => {}}>
<RequestButtonText>SOLICITAR UPERX</RequestButtonText>
</RequestButton>
</Container>
);
}
};