프로젝트로
애완동물과 산책하는 거리를 보여주는 프로젝트이다
그래서
사용자가 산책을 시작하면
서버에 데이터를 보낸다
사용자 + 산책시간 + 현재위치 (위도, 경도)
를 서버로 보낸다.
이렇게 만들것인데
일단 이 기능의 시나리오는
- 사용자가 산책하기 버튼을 클릭
- 사용자 + 날짜 + 산책시간(현재시간) + 현재위치(위도, 경도)를 보냄
- (서버) 산책하기 테이블에 저장 [ 번호 + 사용자 + 시작시간 + 종료시간(null) ] 을 저장
- 모달창으로 주의 사항 및 안내할 내용을 보여준다 확인버튼을 누르면 모달창은 사라짐
- 산책하는 동안 onUserLocationChange로 변화하면 연결해주는 선그어주기? (GPS)기능 필요
- 산책 종료 버튼 클릭
- 사진찍을 수 있는 모달창 띄우기
- 확인을 누르면 사진찍는 페이지
- 취소를 누르면 그냥 종료 되고 서버에 저장되지 않는다
- 확인을 누르면 카메라 실행, 사진을 찍으면 모달창에 사진을 보여주고 다시찍기와 확인 버튼을 보여줌
- 다시찍기는 9번 다시 실행
- (서버) 산책하기 버튼을 누르면 아마존스토레이지에 저장하여 링크 가져오기
- (서버) 가져온 링크를 사용자의 캘린더 테이블에 저장
- 확인하거나 취소 버튼을 누르면 제일 처음 페이지로 넘어감
이렇게 시나리오를 간단하게 짰는데 가능할지는 잘 모르겠다
가장 문제는 5번인데 좀 더 자료을 찾아봐야한다
이 블로그 내용을 보면서 구현해볼것이다
내용은 블로그에 잘 적혀있어서 쉽게 이해할 수 있었다
이 내용을 먼저 쭉 훑어보고 코드를 작성하는 것을 추천한다!
이동경로 지도에 표시하기를 중심으로 코드를 짰다
이블로그도 참고하여 소숫점 반올림하였다!
https://developer-talk.tistory.com/304
여기까지 친구가 해줬던 내용에 조금만 넣어서 트래킹까지 완료했다
근데 너무 자세하게 나와서 가만히 있어도 위치가 자꾸 바뀐다...
이게 아이폰이라 그런건지,, 아무튼!
전체 코드다!
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import MapView, { Marker, Circle, Callout, AnimatedRegion, Polyline, MarkerAnimated } from 'react-native-maps';
// npm i react-native-maps
import { Text, View, StyleSheet, Button, Alert, Modal, Pressable, Image } from 'react-native';
import * as Location from 'expo-location';
// npm i expo-location
import Checkbox from 'expo-checkbox';
//navigation사용할 때 필요
import 'react-native-gesture-handler';
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
const Stack = createStackNavigator();
export default function Walk(navigation) {
const [mapRegion, setmapRegion] = useState({ //나의 위치 usestate
latitude: 36.7987869, //위도
longitude: 127.0757584, //경도
latitudeDelta: 0.005, //확대되는 범위
longitudeDelta: 0.005, //확대되는 범위
});
//이동경로 표시하기
const [gps, setGps] = React.useState([]);
const [latit, setLatit] = React.useState();
const [longit, setLongit] = React.useState();
//모달
const [modalVisible, setModalVisible] = React.useState(false);
useEffect(() => {
(async () => {
//위치 수집 허용하는지 물어보기
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
setErrorMsg('Permission to access location was denied');
return;
}
let location = await Location.getCurrentPositionAsync({});
let address = await Location.reverseGeocodeAsync(location.coords);
console.log(location);
console.log(address);
setmapRegion({ //현재 위치
latitude: location.coords.latitude,
longitude: location.coords.longitude
})
})();
}, []);
const startWalk = () => {
//서버에 시간, 위치 보내기
setModalVisible(true) //test
const date = new Date();
const time = `${date.getFullYear()}/${date.getMonth()}/${date.getDate()} ${date.getHours()}:${date.getMinutes()}`
// axios.post("링크링크", null, {
// params: {
// latitude: latit,
// longitude: longit,
// id: "user",
// time: time, //시작시간
// }
// })
// .then(function (res) {
// console.log(res)
// console.log(res.data)
// if (res.data === true) {
// setModalVisible(true)
// }
// })
}
const walkTo = () => {
//서버에 위치 보내기
console.log("walkTogether")
// axios.post("링크링크" ,null, {
// params : {
// 위도,
// 경도
// }
// })
}
return (
<View style={styles.container}>
<View style={styles.map}>
<MapView
style={{ alignSelf: 'stretch', height: '100%' }}
// region={mapRegion}
// initialRegion={{mapRegion}}
initialRegion={{
latitude: 36.7987869,
longitude: 127.0757584,
latitudeDelta: 0.0005,
longitudeDelta: 0.0005,
}}
//사용자 위치에 맞게 마커가 표시된다.
showsUserLocation={true}
// userLocationUpdateInterval =
onUserLocationChange={(e) => {
//사용자가 이동하면 위치를 저장함
//console.log("onUserLocationChange", e.nativeEvent.coordinate);
//위치 위도경도를 저장함
// 너무 새새하게 나와서 자름!
// 소숫점 4자리까지만 나오게 저장하게 함
//const lat = e.nativeEvent.coordinate.latitude.toFixed(4)
//const long = e.nativeEvent.coordinate.longitude.toFixed(4)
//그래도 정확도를 위해서 위도 경도 모두로 계산할거임
const newCoordinate = {
latitude: e.nativeEvent.coordinate.latitude,
longitude: e.nativeEvent.coordinate.longitude
}
setGps(gps.concat(newCoordinate));
console.log("gps", gps);
// setmapRegion(gps.concat(newCoordinate));
}}
>
{/* 마커표시 */}
<Marker
coordinate={mapRegion}
draggable={true} //마커 드래그 가능
onDragStart={(e) => { console.log("Drag start", e.nativeEvent.coordinate); }} //드래그 한 위도, 경도 나타냄
onDragEnd={(e) => {
const lat = e.nativeEvent.coordinate.latitude.toFixed(4)
const long = e.nativeEvent.coordinate.longitude.toFixed(4)
setmapRegion({
latitude: lat,
longitude: long
});
setLatit(lat)
setLongit(long)
}} //드래그 한 곳으로 마커 이동
>
<Callout>
<Text>This is Callout</Text>
</Callout>
</Marker>
{/* 반경 */}
<Circle center={mapRegion} radius={500} />
<Polyline
coordinates={gps}
strokeColor="#4e90f7"
// coordinates={[
// { latitude: 37.8025259, longitude: -122.4351431 },
// { latitude: 37.7896386, longitude: -122.421646 },
// { latitude: 37.7665248, longitude: -122.4161628 },
// { latitude: 37.7734153, longitude: -122.4577787 },
// { latitude: 37.7948605, longitude: -122.4596065 },
// { latitude: 37.8025259, longitude: -122.4351431 }
// ]}
// strokeColor="#000" // fallback for when `strokeColors` is not supported by the map-provider
// strokeColors={[
// '#7F0000',
// '#00000000', // no color, creates a "long" gradient between the previous and next coordinate
// '#B24112',
// '#E5845C',
// '#238C23',
// '#7F0000'
// ]}
strokeWidth={6}
/>
</MapView>
<View style={styles.buttons}>
{/* 버튼 */}
<Pressable style={styles.button} onPress={startWalk} >
<Text style={styles.text}>start</Text>
</Pressable>
<Text> </Text>
<Pressable style={styles.button} onPress={walkTo}>
<Text style={styles.text}>togher</Text>
</Pressable>
</View>
</View>
</View>
);
};
//{latitudeDelta: 0.0922, longitudeDelta: 0.0421}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
},
map: {
width: "100%",
height: "90%",
},
buttons: {
padding: 10,
height: "10%",
flexDirection: 'row',
widh: "100%",
backgroundColor: 'yellow',
justifyContent: 'center'
},
button: {
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 12,
paddingHorizontal: 32,
borderRadius: 4,
elevation: 3,
backgroundColor: 'orange',
},
centeredView: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginTop: 22,
},
modalView: {
margin: 20,
backgroundColor: 'white',
borderRadius: 20,
padding: 35,
alignItems: 'center',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 4,
elevation: 5,
},
buttonOpen: {
backgroundColor: '#F194FF',
},
buttonClose: {
backgroundColor: '#2196F3',
},
textStyle: {
color: 'white',
fontWeight: 'bold',
textAlign: 'center',
},
modalText: {
marginBottom: 15,
textAlign: 'center',
},
});
상세 코드 정리
<MapView>
: react native map 라이브러리에서 가져온 지도
<MapView
style={{ alignSelf: 'stretch', height: '100%' }}
// region={mapRegion}
// initialRegion={{mapRegion}}
initialRegion={{
latitude: 36.7987869,
longitude: 127.0757584,
latitudeDelta: 0.0005,
longitudeDelta: 0.0005,
}}
//사용자 위치에 맞게 마커가 표시된다.
showsUserLocation={true}
// userLocationUpdateInterval =
onUserLocationChange={(e) => {
//사용자가 이동하면 위치를 저장함
//console.log("onUserLocationChange", e.nativeEvent.coordinate);
//위치 위도경도를 저장함
// 너무 새새하게 나와서 자름!
// 소숫점 4자리까지만 나오게 저장하게 함
const lat = e.nativeEvent.coordinate.latitude.toFixed(4)
const long = e.nativeEvent.coordinate.longitude.toFixed(4)
const newCoordinate = {
latitude: lat,
longitude: long
}
setGps(gps.concat(newCoordinate));
console.log("gps", gps);
// setmapRegion(gps.concat(newCoordinate));
}}
>
아이폰에서는 i-map
갤럭시에서는 google-map이 연동 되어 있다
initialRegion : 위도 경도 초기값
showsUserLocation : 사용자의 현재 위치를 보여줌
onUserLocationChange : 사용자의 위치가 바뀔 떄 마다 event를 발생하도록 하는 프롭스
ㄴ e.nativeEvent.coordinate.latitude.toFixed(4) :: 소숫점 4자리까지 잘라서 벼눗에 저장
ㄴ setGps(gps.concat(newCoordinate)) : useState에 있는 값을 렌더링 해주는 것
렌더링이 될 때마다 사용자가 이동할 때 마다 위도 경도 값이 생성 될 건데 이를 저장하는 배열에 넣는것이다.
concat이 원래 있던 배열에 붙이기? 느낌인거지요
<Marker>
<Marker
coordinate={mapRegion}
draggable={true} //마커 드래그 가능
onDragStart={(e) => { console.log("Drag start", e.nativeEvent.coordinate); }} //드래그 한 위도, 경도 나타냄
onDragEnd={(e) => {
const lat = e.nativeEvent.coordinate.latitude.toFixed(4)
const long = e.nativeEvent.coordinate.longitude.toFixed(4)
setmapRegion({
latitude: lat,
longitude: long
});
setLatit(lat)
setLongit(long)
}} //드래그 한 곳으로 마커 이동
>
coordinate=위도 경도가 있는 정보를 넣어 위치를 알려줌
draggable = 드래그 가능함
onDrageStart , onDragEnd는 드래그한 부분에서 시작과 끝 말 그대로다..!
+++ 마커 대신 이미지 넣기
<Marker
coordinate={{ latitude: item.latitude, longitude: item.longitude }}
onPress={() =>
{
sheetRef.current.snapTo(0);
setmapRegion(mapRegion.map((item, idx) => {
if (index === idx) {
return { ...item, isClick: true };
} else {
return { ...item, isClick: false };
}
}));
}}
image={require('../../assets/path1.png')}
>
image 프롭스가 있다! 여기에 이미지를 삽입하면 된다.
<Callout>
<Callout>
<Text>This is Callout</Text>
</Callout>
Callout : 마커를 클릭했을 때 나오는 것들
View 태그를 넣어서 디자인, 코딩 하면 된다!
<Circle>
{/* 반경 */}
<Circle center={mapRegion} radius={500} />
radius : 원이 만들어지는 반경
<Polyline>
<Polyline
coordinates={gps}
strokeColor="#4e90f7"
// coordinates={[
// { latitude: 37.8025259, longitude: -122.4351431 },
// { latitude: 37.7896386, longitude: -122.421646 },
// { latitude: 37.7665248, longitude: -122.4161628 },
// { latitude: 37.7734153, longitude: -122.4577787 },
// { latitude: 37.7948605, longitude: -122.4596065 },
// { latitude: 37.8025259, longitude: -122.4351431 }
// ]}
// strokeColor="#000" // fallback for when `strokeColors` is not supported by the map-provider
// strokeColors={[
// '#7F0000',
// '#00000000', // no color, creates a "long" gradient between the previous and next coordinate
// '#B24112',
// '#E5845C',
// '#238C23',
// '#7F0000'
// ]}
strokeWidth={6}
/>
위도 경도만 있어도 선을 그어주는 것임
상단에 onUserLocationChange에서 계속 concat 해줬던 부분에서
값을 넣어서 선을 그어질 수 있다
strolkeColor = 선색
strokeColors = 여러 선색을 만들 수 있다(ios에서만 가능)
프로젝트를 진행하면서 사용했던 라이브러리를 정리했다
매번 느끼는 것이지만 document를 보면서 정리하면 충분히 개발 할 수 있다는 것을 다른 사람도 느낄 수 있으면 좋겠다!
어려운 것도 많겠지만, 할 수 있다. 해야한다는 생각을 가지고 있으면 좋다
'프론트 > React Native, React' 카테고리의 다른 글
[리액트네이티브] react-native 값 다음 컴포넌트로 전달하기 (Expo) (0) | 2023.07.08 |
---|---|
[리액트 네이티브] react native 확인 취소 알림창(Alert) 띄우기 (0) | 2023.07.07 |
[리액트네이티브] react-native 날씨 가져오기(Expo) (0) | 2023.06.27 |
[리액트네이티브] react-native firebase 연동 파이어베이스 연동 (0) | 2023.06.26 |
[리액트네이티브] react-native firebase firestore 데이터 읽기 (0) | 2023.06.26 |