이전 포스팅에서는 네이버 지도 API를 사용하여 화면에 지도를 표시하고 현재 위치를 표시하는 예제를 만들었다.
이어서 네이버 지도를 클릭했을 때 마커가 표시되는 것과 동시에 해당 주소를 Toast 메시지로 나타내고자 한다.
네이버 지도의 OnMapClick() 이벤트를 통해 좌표 값을 얻을 수 있으며 Geocoder를 사용하여 좌표 값을 주소로 변환할 수 있다.
setOnMapClickListener() 메서드로 OnMapClickListener를 지정하면 지도에 대한 클릭 이벤트를 받을 수 있다. 지도가 클릭되면 onMapClick() 콜백 메서드가 호출되며 파라미터로 클릭된 지점의 좌표가 전달된다.
override fun onMapReady(naverMap: NaverMap) {
this.naverMap = naverMap
// 지도가 클릭 되면 onMapClick() 콜백 메서드가 호출 되며, 파라미터로 클릭된 지점의 화면 좌표와 지도 좌표가 전달 된다.
naverMap.setOnMapClickListener { point, coord ->
Toast.makeText(
this, "${coord.latitude}, ${coord.longitude}",
Toast.LENGTH_SHORT
).show()
}
// 지도가 롱 클릭 되면 onMapLongClick() 콜백 메서드가 호출 되며, 파라미터로 클릭된 지점의 화면 좌표와 지도 좌표가 전달 된다.
naverMap.setOnMapLongClickListener { point, coord ->
Toast.makeText(
this, "${coord.latitude}, ${coord.longitude}",
Toast.LENGTH_SHORT
).show()
}
}
마커는 지도상의 한 지점을 나타내기 위한 오버레이로 지도에서 가장 널리 사용되는 요소이다.
객체를 생성하고 position 속성에 좌표를 지정한 후 map 속성에 지도 객체를 지정하면 마커가 나타난다.
📌 마커 추가
val marker = Marker() marker.position = LatLng(37.5670135, 126.9783740) marker.map = naverMap
📌 마커 삭제
marker.map = null
private val marker = Marker()
override fun onMapReady(naverMap: NaverMap) {
this.naverMap = naverMap
naverMap.setOnMapClickListener { point, coord ->
Toast.makeText(
marker.position = LatLng(coord.latitude, coord.longitude)
marker.map = naverMap
).show()
}
}
안드로이드에서는 위도와 경도를 이용해서 주소를 구하는 경우나 역으로 주소를 이용해서 위도와 경도를 구하는 경우 GeoCoding이 사용된다.
📌 Geocoder
GeoCoding(지오코딩) : 주소를 가지고 위도와 경도를 구한다.
Reverse-GeoCoding(역지오코딩) : 위도와 경도를 가지고 주소를 구한다.
- 위도, 경도를 주소로 반환 할 때의 반환 값
- getAddressLine(0) : 전체 주소
- adminArea : 시, 도
- locality, subLocality : 구
- thoroughfare : 동
- subThoroughfare : 번지
- featureName : 세부주소
- postalCode : 우편번호
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
private val marker = Marker()
override fun onMapReady(naverMap: NaverMap) {
this.naverMap = naverMap
// 지도가 클릭 되면 onMapClick() 콜백 메서드가 호출 되며, 파라미터로 클릭된 지점의 화면 좌표와 지도 좌표가 전달 된다.
naverMap.setOnMapClickListener { point, coord ->
marker(coord.latitude, coord.longitude)
}
}
// 클릭 된 지점의 좌표에 마커를 추가하는 함수
private fun marker(latitude: Double, longitude: Double) {
marker.position = LatLng(latitude, longitude)
marker.map = naverMap
getAddress(latitude, longitude)
}
// 클릭 된 지점의 좌표에 대한 주소를 구하는 함수
private fun getAddress(latitude: Double, longitude: Double) {
// Geocoder 선언
val geocoder = Geocoder(applicationContext, Locale.KOREAN)
// 안드로이드 API 레벨이 33 이상인 경우
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
geocoder.getFromLocation(
latitude, longitude, 1
) { address ->
if (address.size != 0) {
// 반환 값에서 전체 주소만 사용한다.
// getAddressLine(0)
toast(address[0].getAddressLine(0))
}
}
} else { // API 레벨이 33 미만인 경우
val addresses = geocoder.getFromLocation(latitude, longitude, 1)
if (addresses != null) {
toast(addresses[0].getAddressLine(0))
}
}
}
private fun toast(text: String) {
runOnUiThread {
Toast.makeText(applicationContext, text, Toast.LENGTH_SHORT).show()
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".naver_map.MapViewActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/map_fragment"
android:name="com.naver.maps.map.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
class MapViewActivity : AppCompatActivity(), OnMapReadyCallback {
private val LOCATION_PERMISSION_REQUEST_CODE = 5000
private val PERMISSIONS = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
private lateinit var binding: ActivityMapViewBinding
private lateinit var naverMap: NaverMap
private lateinit var locationSource: FusedLocationSource
private val TAG = MapViewActivity::class.simpleName
private val marker = Marker()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_map_view)
if (!hasPermission()) {
ActivityCompat.requestPermissions(this, PERMISSIONS, LOCATION_PERMISSION_REQUEST_CODE)
} else {
initMapView()
}
}
private fun initMapView() {
val fm = supportFragmentManager
val mapFragment = fm.findFragmentById(R.id.map_fragment) as MapFragment?
?: MapFragment.newInstance().also {
fm.beginTransaction().add(R.id.map_fragment, it).commit()
}
mapFragment.getMapAsync(this)
locationSource = FusedLocationSource(this, LOCATION_PERMISSION_REQUEST_CODE)
}
private fun hasPermission(): Boolean {
for (permission in PERMISSIONS) {
if (ContextCompat.checkSelfPermission(this, permission)
!= PackageManager.PERMISSION_GRANTED
) {
return false
}
}
return true
}
override fun onMapReady(naverMap: NaverMap) {
this.naverMap = naverMap
naverMap.locationSource = locationSource
naverMap.uiSettings.isLocationButtonEnabled = true
naverMap.locationTrackingMode = LocationTrackingMode.Follow
naverMap.setOnMapClickListener { point, coord ->
marker(coord.latitude, coord.longitude)
}
}
private fun marker(latitude: Double, longitude: Double) {
marker.position = LatLng(latitude, longitude)
marker.map = naverMap
getAddress(latitude, longitude)
}
private fun getAddress(latitude: Double, longitude: Double) {
val geocoder = Geocoder(applicationContext, Locale.KOREAN)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
geocoder.getFromLocation(
latitude, longitude, 1
) { address ->
if (address.size != 0) {
toast(address[0].getAddressLine(0))
}
}
} else {
val addresses = geocoder.getFromLocation(latitude, longitude, 1)
if (addresses != null) {
toast(addresses[0].getAddressLine(0))
}
}
}
private fun toast(text: String) {
runOnUiThread {
Toast.makeText(applicationContext, text, Toast.LENGTH_SHORT).show()
}
}
}