728x90
매니페스트, xml, 종속성 추가 과정
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mapwithmarker">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<!--
The API key for Google Maps-based APIs.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}" />
<activity
android:name=".MapsMarkerActivity"
android:label="@string/title_activity_maps"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
xml
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.mapwithmarker.MapsMarkerActivity" />
dependencies 에 라이브러리 추가
implementation ("com.google.android.gms:play-services-maps:18.2.0")
implementation ("com.google.android.gms:play-services-location:21.1.0")
Activity의 onCreate() 메서드에서 레이아웃 파일을 콘텐츠 뷰로 설정합니다. FragmentManager.findFragmentById()를 호출하여 지도 프래그먼트의 핸들을 가져옵니다. 그런 다음 getMapAsync()를 사용하여 지도 콜백에 등록합니다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Retrieve the content view that renders the map.
setContentView(R.layout.activity_maps)
// Get the SupportMapFragment and request notification when the map is ready to be used.
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as? SupportMapFragment
mapFragment?.getMapAsync(this)
}
OnMapReadyCallback 인터페이스를 구현하고, GoogleMap 객체를 사용할 수 있을 때 지도를 설정하도록 onMapReady() 메서드를 재정의합니다.
class MapsMarkerActivity : AppCompatActivity(), OnMapReadyCallback {
// ...
override fun onMapReady(googleMap: GoogleMap) {
val sydney = LatLng(-33.852, 151.211)
googleMap.addMarker(
MarkerOptions()
.position(sydney)
.title("Marker in Sydney")
)
}
}
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
/**
* 특정 위치를 나타내는 마커(핀)와 함께 Google 지도를 표시하는 활동입니다.
*/
class MapsMarkerActivity : AppCompatActivity(), OnMapReadyCallback {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Retrieve the content view that renders the map.
setContentView(R.layout.activity_maps)
//SupportMapFragment를 가져오고 지도를 사용할 준비가 되면 알림을 요청합니다.
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as? SupportMapFragment
mapFragment?.getMapAsync(this)
}
override fun onMapReady(googleMap: GoogleMap) {
val sydney = LatLng(-33.852, 151.211)
googleMap.addMarker(
MarkerOptions()
.position(sydney)
.title("Marker in Sydney")
)
googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
}
}
지도에서 사용자 이벤트 처리
- GoogleMap.OnMapClickListener: 지도 클릭 이벤트
- GoogleMap.OnMapLongClickListener: 지도 롱 클릭 이벤트
- GoogleMap.OnMarkerClickListener: 마커 클릭 이벤트
- GoogleMap.OnMarkerDragListener: 마커 드래그 이벤트
- GoogleMap.OnInfoWindowClickListener: 정보 창 클릭 이벤트
- GoogleMap.OnCameraIdleListener: 지도 화면 변경 이벤트
googleMap?.setOnMapClickListener { latLng ->
Log.d("map_test", "click : ${latLng.latitude} , ${latLng.longitude}")
}
googleMap?.setOnMapLongClickListener { latLng ->
Log.d("map_test", "long click : ${latLng.latitude} , ${latLng.longitude}")
}
googleMap?.setOnCameraIdleListener {
val position = googleMap!!.cameraPosition
val zoom = position.zoom
val latitude = position.target.latitude
val longitude = position.target.longitude
Log.d("map_test", "User change : $zoom $latitude , $longitude")
}
googleMap?.setOnMarkerClickListener { marker ->
true
}
googleMap?.setOnInfoWindowClickListener { marker ->
}
참고
https://developers.google.com/maps/documentation/android-sdk/map-with-marker?hl=ko#kotlin
https://developers.google.com/maps/documentation/android-sdk/config?hl=ko
간단한 예제
import android.Manifest
import android.content.pm.PackageManager
import android.location.Location
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.util.Log
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat
import com.example.googlemap.databinding.ActivityMainBinding
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
class MainActivity : AppCompatActivity(), OnMapReadyCallback {
private var _binding: ActivityMainBinding? = null
private val binding get() = _binding!!
lateinit var mGoogleMap: GoogleMap
lateinit var fusedLocationClient: FusedLocationProviderClient //위치 서비스
lateinit var locationCallback: LocationCallback //위치 정보 받기 위한 콜백
lateinit var locationPermission: ActivityResultLauncher<Array<String>> //퍼미션
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
locationPermission =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
if (result.all { it.value }) {
(supportFragmentManager.findFragmentById(R.id.mapView) as SupportMapFragment)!!.getMapAsync(
this
)//getMapAsync -> onMapReady
} else {//문제 발생시
Toast.makeText(this, "권한 승인이 필요합니다.", Toast.LENGTH_SHORT).show()
}
}
//권한 요청
locationPermission.launch(
arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
),
)
}
//지도 객체를 이용할 수 있는 상황이 될 때 /권한 허용된 상태라면 getMapAsync
override fun onMapReady(p0: GoogleMap) {
//onMapReady가 되면 마커 하나
val seoul = LatLng(37.566610, 126.978403)
mGoogleMap = p0
mGoogleMap.mapType = GoogleMap.MAP_TYPE_NORMAL // default 노말 생략 가능
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 {
interval = 1000 //1초 마다 갱신
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.")
setLastLocation(location)//계속 실시간으로 위치를 받아오고 있기 때문에 맵을 확대해도 다시 줄어든다.
}
}
}
}
//권한 처리
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
}
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))
}
}