728x90
1. 지도 사용 설정하기
- build.gradle의 dependencies 추가
implementation("com.google.android.gms:play-services-maps:18.2.0")
implementation("com.google.android.gms:play-services-location:21.0.1")
- 퍼미션 추가
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
- 구글 지도 API 이용하는 키 등록
<uses-library android:name="org.apache.http.legacy" android:required="true"/>
<meta-data android:name="com.google.android.maps.v2.API_KEY"
android:value="구글 지도 API 키"/>
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"/>
2. 구글 개발자 콘솔에서 지도 API 키 얻기
- 구글 개발자 콘솔에 접속해 프로젝트를 생성하고 사용자 인증 정보를 만들면 지도 API 키를 발급받을 수 있다
(무료 사용 하는데도 카드는 등록해야 한다..) - 구글 개발자 콘솔에서 얻은 지도 API키를 ManiFest파일에 등록해 준다
- 레이아웃.xml
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.google.android.gms.maps.SupportMapFragment"/>
3. 지도 제어하기
- 지도의 중심 이동하기
- 지도를 출력하는 뷰 객체를 얻어야 한다
class MainActivity : AppCompatActivity(), OnMapReadyCallback {
var googleMap: GoogleMap? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
(supportFragmentManager.findFragmentById(R.id.mapView) as SupportMapFragment)!!.getMapAsync(this)
// 지도 객체를 이용할 수 있는 상황이 될 때
override fun onMapReady(p0: GoogleMap?) {
googleMap = p0
}
}
- 지도의 중심을 이동
val latLng = LatLng(37.566610, 126.978403)
val position = CameraPosition.Builder()
.target(latLng)
.zoom(18f)
.build()
googleMap?.moveCamera(CameraUpdateFactory.newCameraPosition(position))
- 마커 표시하기
val markerOptions = MarkerOptions()
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_marker))
markerOptions.position(latLng)
markerOptions.title("서울시청")
markerOptions.snippet("Tel:01-120")
googleMap?.addMarker(markerOptions)
- 위치 요청
val locationRequest = LocationRequest.create().apply {
interval = 1000
fastestInterval = 500
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
locationCallback = object : LocationCallback(){
//1초에 한번씩 변경된 위치 정보가 onLocationResult 으로 전달된다.
override fun onLocationResult(locationResult: LocationResult) {
locationResult?.let{
for (location in it.locations){
Log.d("위치정보", "위도: ${location.latitude} 경도: ${location.longitude}")
}
}
}
}
- 지도에서 사용자 이벤트 처리
GoogleMap.OnMapClickListener : 지도 클릭 이벤트
GoogleMap.OnMapLongClickListener : 지도 롱 클릭 이벤트
GoogleMap.OnMarkerClickListener : 마커 클릭 이벤트
GoogleMap.OnMarkerDragListener : 마커 드래그 이벤트
GoogleMap.OnInfoWindowClickListener : 정보 창 클릭 이벤트
GoogleMap.OnCameraIdleListener : 지도 화면 변경 이벤트
MainActivity.kt
더보기
class MainActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var mGoogleMap: GoogleMap
// 위치 서비스가 gps를 사용해서 위치를 확인
lateinit var fusedLocationClient: FusedLocationProviderClient
// 위치 값 요청에 대한 갱신 정보를 받는 변수
lateinit var locationCallback: LocationCallback
lateinit var locationPermission: ActivityResultLauncher<Array<String>>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
locationPermission = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { results ->
if (results.all { it.value }) {
(supportFragmentManager.findFragmentById(R.id.mapView) as SupportMapFragment)!!.getMapAsync(
this
)
} else { // 문제가 발생 했을 때
Toast.makeText(this, "권한 승인이 필요합니다.", Toast.LENGTH_SHORT).show()
}
}
// 권한 요청
locationPermission.launch(
arrayOf(
android.Manifest.permission.ACCESS_COARSE_LOCATION,
android.Manifest.permission.ACCESS_FINE_LOCATION
)
)
}
// 지도 객체를 이용할 수 있는 상황이 될 때
override fun onMapReady(p0: GoogleMap) {
val seoul = LatLng(37.566610, 126.978403)
mGoogleMap = p0
// default 노말 생략 가능
mGoogleMap.mapType = GoogleMap.MAP_TYPE_NORMAL
mGoogleMap.apply {
val markerOptions = MarkerOptions()
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))
markerOptions.position(seoul)
markerOptions.title("서울시청")
markerOptions.snippet("Tel:01-120")
addMarker(markerOptions)
}
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
updateLocation()
}
fun updateLocation() {
val locationRequest = LocationRequest.create().apply {
// 업데이트 간격 단위(ms)
interval = 1000
// 가장 빠른 업데이트 간격 단위(ms)
fastestInterval = 500
// 정확성
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
locationCallback = object : LocationCallback() {
// 1초에 한번씩 변경된 위치 정보가 onLocationResult로 전달된다.
override fun onLocationResult(locationResult: LocationResult) {
locationResult?.let {
for (location in it.locations) {
Log.d("위치정보", "위도: ${location.latitude} 경도: ${location.longitude}")
// 계속 실시간으로 위치를 받아오고 있기 때문에 맵을 확대해도 다시 줄어든다
setLastLocation(location)
}
}
}
}
// 권한 처리
if (ActivityCompat.checkSelfPermission(
this,
android.Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this,
android.Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
}
// 기기의 위치에 관한 정기 업데이트를 요청하는 메서드 실행
// 지정한 루퍼 스레드(Looper.myLooper()!!)에서 콜백(locationCallback)으로 위치 업데이트를 요청한다
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback,
Looper.myLooper()!!
)
}
fun setLastLocation(lastLocation: Location) {
val LATLNG = LatLng(lastLocation.latitude, lastLocation.longitude)
val markerOptions = MarkerOptions().position(LATLNG).title("현재 위치")
val cameraPosition = CameraPosition.Builder().target(LATLNG).zoom(15.0f).build()
mGoogleMap.addMarker(markerOptions)
mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))
}
}
728x90
'코틀린(Kotlin) > TIL' 카테고리의 다른 글
[코틀린(Kotlin)] CLEARTEXT communication to XXXX not permitted by network security policy (0) | 2024.01.31 |
---|---|
[코틀린(Kotlin)] 레트로 핏(Retrofit) (1) | 2024.01.29 |
[코틀린(Kotlin)] 사용자의 위치 얻기 (0) | 2024.01.25 |
[코틀린(Kotlin)] 데이터 저장 - SharedPreference, Room (0) | 2024.01.24 |
[코틀린(Kotlin)] RecyclerView - StickyHeader, 스크롤 시 상단 뷰 고정 (0) | 2024.01.19 |