이 Codelab은 Kotlin 기반 Android 고급 교육 과정의 일부입니다. Codelab을 순서대로 진행하는 경우 학습 효과를 극대화할 수 있지만 순서를 바꿔 진행해도 괜찮습니다. 모든 교육 과정 Codelab은 Kotlin 기반 고급 Android Codelab 방문 페이지에 나열되어 있습니다.
Google 지도로 앱을 빌드하면 위성 이미지, 지도의 강력한 UI 컨트롤, 위치 추적, 위치 마커와 같은 기능을 앱에 추가할 수 있습니다. 유명한 낚시 또는 등반 지역의 위치와 같은 자체 데이터 세트의 정보를 표시하여 표준 Google 지도에 가치를 더할 수 있습니다. 플레이어가 보물찾기나 증강 현실 게임처럼 실제 세계를 탐험하는 게임을 만들 수도 있습니다.
이 수업에서는 맞춤 지도를 표시하고 사용자의 위치를 보여주는 Wander라는 Google 지도 앱을 만듭니다.
기본 요건
다음 사항에 대한 지식
- Android 스튜디오를 사용하여 기본 Android 앱을 만들고 실행하는 방법
- 문자열과 같은 리소스를 만들고 관리하는 방법
- Android 스튜디오를 사용하여 코드를 리팩터링하고 변수 이름을 바꾸는 방법
- 사용자로서 Google 지도를 사용하는 방법
- 런타임 권한을 설정하는 방법
학습할 내용
- Google API 콘솔에서 API 키를 가져와 앱에 등록하는 방법
- 앱에 Google 지도를 통합하는 방법
- 다양한 지도 유형을 표시하는 방법
- Google 지도 스타일을 지정하는 방법
- 지도에 마커를 추가하는 방법
- 사용자가 관심 장소 (POI)에 마커를 배치할 수 있도록 하는 방법
- 위치 추적을 사용 설정하는 방법
- Google 지도가 삽입된
Wander
앱을 만드는 방법 - 마커, 스타일 지정 등 앱의 맞춤 기능을 만드는 방법
- 앱에서 위치 추적을 사용 설정하는 방법
이 Codelab에서는 맞춤 스타일이 적용된 Google 지도를 표시하는 Wander
앱을 만듭니다. Wander 앱을 사용하면 위치에 마커를 배치하고, 오버레이를 추가하고, 내 위치를 실시간으로 확인할 수 있습니다.
Android용 Maps SDK에는 API 키가 필요합니다. API 키를 가져오려면 API 및 서비스 페이지에 프로젝트를 등록하세요. API 키는 앱을 작성자와 연결하는 디지털 인증서에 연결됩니다. 디지털 인증서 사용 및 앱 서명에 관한 자세한 내용은 앱 서명을 참고하세요.
이 Codelab에서는 디버그 인증서의 API 키를 사용합니다. 디버그 인증서는 디버그 빌드 서명에 설명된 대로 설계상 보안이 유지되지 않습니다. Android용 Maps SDK를 사용하는 게시된 Android 앱에는 출시 인증서의 키인 두 번째 API 키가 필요합니다. 출시 인증서 획득에 대한 자세한 내용은 API 키 가져오기를 참고하세요.
Android 스튜디오에는 유용한 템플릿 코드를 생성하는 Google 지도 활동 템플릿이 포함되어 있습니다. 템플릿 코드에는 API 키를 쉽게 가져올 수 있는 링크가 포함된 google_maps_api.xml 파일이 포함되어 있습니다.
1단계: 지도 템플릿으로 Wander 프로젝트 만들기
- 새 Android 스튜디오 프로젝트를 만듭니다.
- Google 지도 활동 템플릿을 선택합니다.
- 프로젝트 이름을
Wander
로 지정합니다. - 최소 API 수준을 API 19로 설정합니다. 언어가 Kotlin인지 확인합니다.
- 마침을 클릭합니다.
- 앱 빌드가 완료되면 프로젝트와 Android 스튜디오에서 생성한 다음 지도 관련 파일을 살펴봅니다.
google_maps_api.xml: 이 구성 파일을 사용하여 API 키를 저장합니다. 템플릿은 디버그용과 출시용의 두 가지 google_maps_api.xml 파일을 생성합니다. 디버그 인증서의 API 키 파일은 src/debug/res/values에 있습니다. 출시 인증서의 API 키 파일은 src/release/res/values에 있습니다. 이 Codelab에서는 디버그 인증서만 사용합니다.
activity_maps.xml - 이 레이아웃 파일에는 전체 화면을 채우는 단일 프래그먼트가 포함되어 있습니다. SupportMapFragment
클래스는 Fragment
클래스의 서브클래스입니다. SupportMapFragment
은 앱에 지도를 배치하는 가장 간단한 방법입니다. 필요한 수명 주기 요구사항을 자동으로 처리하는 지도 뷰의 래퍼입니다.
name
속성이 추가된 ViewGroup
에서 <fragment>
태그를 사용하여 레이아웃 파일에 SupportMapFragment
를 포함할 수 있습니다.
android:name="com.google.android.gms.maps.SupportMapFragment"
MapsActivity.java - MapsActivity.kt 파일은 onCreate()
메서드에서 SupportMapFragment
를 인스턴스화하고 클래스의 getMapAsync
()
를 사용하여 지도 시스템과 뷰를 자동으로 초기화합니다. SupportMapFragment
을 포함하는 활동은 OnMapReadyCallback
인터페이스와 해당 인터페이스의 onMapReady()
메서드를 구현해야 합니다. 지도가 로드되면 onMapReady()
메서드가 호출됩니다.
2단계: API 키 가져오기
- google_maps_api.xml 파일의 디버그 버전을 엽니다.
- 파일에서 긴 URL이 포함된 댓글을 찾습니다. URL의 매개변수에는 앱에 관한 구체적인 정보가 포함됩니다.
- URL을 복사하여 브라우저에 붙여넣습니다.
- 메시지에 따라 API 및 서비스 페이지에서 프로젝트를 만듭니다. 제공된 URL의 매개변수 때문에 페이지에서 Android용 Maps SDK를 자동으로 사용 설정합니다.
- API 키 만들기를 클릭합니다.
- 다음 페이지에서 API 키 섹션으로 이동하여 방금 만든 키를 클릭합니다.
- 키 제한을 클릭하고 Android용 Maps SDK를 선택하여 키 사용을 Android 앱으로 제한합니다.
- 생성된 API 키를 복사합니다. '
AIza"
'로 시작합니다. google_maps_api.xml
파일에서YOUR_KEY_HERE
이라고 표시된google_maps_key
문자열에 키를 붙여넣습니다.- 앱을 실행합니다. 오스트레일리아 시드니에 마커가 설정된 지도가 활동에 삽입되어 표시됩니다. (시드니 마커는 템플릿의 일부이며 나중에 변경할 수 있습니다.)
3단계: mMap 이름 바꾸기
MapsActivity
에는 GoogleMap
유형의 비공개 lateinit
var
(mMap
)이 있습니다. Kotlin 이름 지정 규칙을 따르려면 mMap
의 이름을 map
로 변경하세요.
MapsActivity
에서mMap
를 마우스 오른쪽 버튼으로 클릭하고 리팩터링> 이름 바꾸기...를 클릭합니다.
- 변수 이름을
map
로 변경합니다.
onMapReady()
함수의 mMap
에 대한 모든 참조도 map
로 변경됩니다.
Google 지도에는 일반, 하이브리드, 위성, 지형, '없음' (지도를 표시하지 않음) 등 여러 지도 유형이 포함되어 있습니다.
일반 지도 | 위성 지도 | 하이브리드 지도 | 지형 지도 |
지도 유형마다 다른 종류의 정보가 제공됩니다. 예를 들어 자동차에서 내비게이션을 위해 지도를 사용하는 경우 거리 이름을 보는 것이 유용하므로 일반 옵션을 사용할 수 있습니다. 하이킹을 할 때 지형 지도는 정상까지 얼마나 더 올라가야 하는지 결정하는 데 도움이 될 수 있습니다.
이 작업에서는 다음을 수행합니다.
- 사용자가 지도 유형을 변경할 수 있는 옵션 메뉴가 있는 앱 바를 추가합니다.
- 지도의 시작 위치를 내 집 위치로 이동합니다.
- 지도에서 단일 위치를 나타내고 라벨을 포함할 수 있는 마커 지원 추가
지도 유형 메뉴 추가
이 단계에서는 사용자가 지도 유형을 변경할 수 있는 옵션 메뉴가 있는 앱 바를 추가합니다.
- 새 메뉴 XML 파일을 만들려면 res 디렉터리를 마우스 오른쪽 버튼으로 클릭하고 New> Android Resource File을 선택합니다.
- 대화상자에서 파일 이름을
map_options
로 지정합니다. - 리소스 유형으로 메뉴를 선택합니다.
- 확인을 클릭합니다.
- 코드 탭에서 새 파일의 코드를 다음 코드로 바꿔 지도 메뉴 옵션을 만듭니다. '없음' 지도 유형은 '없음'을 선택하면 지도가 전혀 표시되지 않으므로 생략됩니다. 이 단계에서 오류가 발생하지만 다음 단계에서 해결합니다.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/normal_map"
android:title="@string/normal_map"
app:showAsAction="never" />
<item
android:id="@+id/hybrid_map"
android:title="@string/hybrid_map"
app:showAsAction="never" />
<item
android:id="@+id/satellite_map"
android:title="@string/satellite_map"
app:showAsAction="never" />
<item
android:id="@+id/terrain_map"
android:title="@string/terrain_map"
app:showAsAction="never" />
</menu>
strings.xml
에서title
속성의 리소스를 추가하여 오류를 해결합니다.
<resources>
...
<string name="normal_map">Normal Map</string>
<string name="hybrid_map">Hybrid Map</string>
<string name="satellite_map">Satellite Map</string>
<string name="terrain_map">Terrain Map</string>
<string name="lat_long_snippet">Lat: %1$.5f, Long: %2$.5f</string>
<string name="dropped_pin">Dropped Pin</string>
<string name="poi">poi</string>
</resources>
MapsActivity
에서onCreateOptionsMenu()
메서드를 재정의하고map_options
리소스 파일에서 메뉴를 확장합니다.
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.map_options, menu)
return true
}
MapsActivity.kt
에서onOptionsItemSelected()
메서드를 재정의합니다. 지도 유형 상수를 사용하여 사용자의 선택을 반영하도록 지도 유형을 변경합니다.
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
// Change the map type based on the user's selection.
R.id.normal_map -> {
map.mapType = GoogleMap.MAP_TYPE_NORMAL
true
}
R.id.hybrid_map -> {
map.mapType = GoogleMap.MAP_TYPE_HYBRID
true
}
R.id.satellite_map -> {
map.mapType = GoogleMap.MAP_TYPE_SATELLITE
true
}
R.id.terrain_map -> {
map.mapType = GoogleMap.MAP_TYPE_TERRAIN
true
}
else -> super.onOptionsItemSelected(item)
}
- 앱을 실행합니다.
아이콘을 클릭하여 지도 유형을 변경합니다. 모드에 따라 지도의 모양이 어떻게 달라지는지 확인하세요.
기본적으로 onMapReady()
콜백에는 Google 지도가 생성된 오스트레일리아 시드니에 마커를 배치하는 코드가 포함되어 있습니다. 기본 콜백은 지도를 애니메이션 처리하여 시드니로 이동합니다.
이 작업에서는 지도의 카메라가 집으로 이동하고, 지정한 수준으로 확대/축소되며, 마커가 배치됩니다.
1단계: 집으로 확대하고 마커 추가하기
MapsActivity.kt
파일에서onMapReady()
메서드를 찾습니다. 시드니에 마커를 배치하고 카메라를 이동하는 코드를 삭제합니다. 이제 메서드가 다음과 같이 표시됩니다.
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
}
- 이 안내에 따라 집의 위도와 경도를 찾습니다.
- 위도 값과 경도 값을 만들고 부동 소수점 값을 입력합니다.
val latitude = 37.422160
val longitude = -122.084270
homeLatLng
라는 새LatLng
객체를 만듭니다.homeLatLng
객체에서 방금 만든 값을 전달합니다.
val homeLatLng = LatLng(latitude, longitude)
- 지도에서 원하는 확대/축소 수준에 대한
val
를 만듭니다. 확대/축소 수준 15f를 사용합니다.
val zoomLevel = 15f
확대/축소 수준은 지도에서 얼마나 확대되었는지를 제어합니다. 다음 목록은 각 확대/축소 수준에서 표시되는 세부정보 수준을 보여줍니다.
1
: 전 세계5
: 대륙10
: 도시15
: 도로20
: 건물
map
객체에서moveCamera()
함수를 호출하여 카메라를homeLatLng
로 이동하고CameraUpdateFactory.newLatLngZoom()
를 사용하여CameraUpdate
객체를 전달합니다.homeLatLng
객체와zoomLevel
를 전달합니다.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
homeLatLng
에 지도 마커를 추가합니다.
map.addMarker(MarkerOptions().position(homeLatLng))
최종 메서드는 다음과 같습니다.
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
//These coordinates represent the latitude and longitude of the Googleplex.
val latitude = 37.422160
val longitude = -122.084270
val zoomLevel = 15f
val homeLatLng = LatLng(latitude, longitude)
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
map.addMarker(MarkerOptions().position(homeLatLng))
}
- 앱을 실행합니다. 지도가 집으로 이동하고, 원하는 수준으로 확대되며, 집에 마커가 배치됩니다.
2단계: 사용자가 길게 클릭하여 마커를 추가하도록 허용
이 단계에서는 사용자가 지도에서 위치를 터치하고 있으면 마커를 추가합니다.
GoogleMap
를 인수로 사용하는MapsActivity
에서setMapLongClick()
이라는 메서드 스텁을 만듭니다.- 지도 객체에
setOnMapLongClickListener
리스너를 연결합니다.
private fun setMapLongClick(map:GoogleMap) {
map.setOnMapLongClickListener { }
}
setOnMapLongClickListener()
에서addMarker()
메서드를 호출합니다. 위치가 전달된LatLng
로 설정된 새MarkerOptions
객체를 전달합니다.
private fun setMapLongClick(map: GoogleMap) {
map.setOnMapLongClickListener { latLng ->
map.addMarker(
MarkerOptions()
.position(latLng)
)
}
}
onMapReady()
메서드의 끝에서map
를 사용하여setMapLongClick()
를 호출합니다.
override fun onMapReady(googleMap: GoogleMap) {
...
setMapLongClick(map)
}
- 앱을 실행합니다.
- 지도를 길게 터치하여 위치에 마커를 배치합니다.
- 마커를 탭하면 화면 중앙에 표시됩니다.
3단계: 마커에 정보 창 추가
이 단계에서는 마커를 탭할 때 마커의 좌표를 표시하는 InfoWindow
를 추가합니다.
setMapLongClick()setOnMapLongClickListener()
에서snippet
의val
을 만듭니다. 스니펫은 제목 뒤에 표시되는 추가 텍스트입니다. 스니펫에 마커의 위도와 경도가 표시됩니다.
private fun setMapLongClick(map: GoogleMap) {
map.setOnMapLongClickListener { latLng ->
// A snippet is additional text that's displayed after the title.
val snippet = String.format(
Locale.getDefault(),
"Lat: %1$.5f, Long: %2$.5f",
latLng.latitude,
latLng.longitude
)
map.addMarker(
MarkerOptions()
.position(latLng)
)
}
}
addMarker()
에서R.string.
dropped_pin
문자열 리소스를 사용하여 마커의title
을 Dropped Pin으로 설정합니다.- 마커의
snippet
을snippet
로 설정합니다.
완성된 함수는 다음과 같습니다.
private fun setMapLongClick(map: GoogleMap) {
map.setOnMapLongClickListener { latLng ->
// A Snippet is Additional text that's displayed below the title.
val snippet = String.format(
Locale.getDefault(),
"Lat: %1$.5f, Long: %2$.5f",
latLng.latitude,
latLng.longitude
)
map.addMarker(
MarkerOptions()
.position(latLng)
.title(getString(R.string.dropped_pin))
.snippet(snippet)
)
}
}
- 앱을 실행합니다.
- 지도를 길게 터치하여 위치 마커를 고정합니다.
- 마커를 탭하여 정보 창을 표시합니다.
4단계: 관심 장소 리스너 추가
기본적으로 관심 장소 (POI)는 해당 아이콘과 함께 지도에 표시됩니다. 관심 장소에는 공원, 학교, 정부 건물 등이 포함됩니다. 지도 유형이 normal
로 설정된 경우 비즈니스 관심 장소도 지도에 표시됩니다. 비즈니스 관심 장소는 상점, 음식점, 호텔 등의 비즈니스를 나타냅니다.
이 단계에서는 GoogleMap.OnPoiClickListener
을 지도에 추가합니다. 이 클릭 리스너는 사용자가 관심 장소를 클릭하면 즉시 지도에 마커를 배치합니다. 클릭 리스너는 관심 장소 이름이 포함된 정보 창도 표시합니다.
GoogleMap
를 인수로 사용하는MapsActivity
에서setPoiClick()
이라는 메서드 스텁을 만듭니다.setPoiClick()
메서드에서 전달된GoogleMap
에OnPoiClickListener
를 설정합니다.
private fun setPoiClick(map: GoogleMap) {
map.setOnPoiClickListener { poi ->
}
}
setOnPoiClickListener()
에서 마커의val poiMarker
을 만듭니다 .map.addMarker()
를 사용하여 마커로 설정하고MarkerOptions
를 사용하여title
를 관심 장소의 이름으로 설정합니다.
private fun setPoiClick(map: GoogleMap) {
map.setOnPoiClickListener { poi ->
val poiMarker = map.addMarker(
MarkerOptions()
.position(poi.latLng)
.title(poi.name)
)
}
}
setOnPoiClickListener()
함수에서poiMarker
에showInfoWindow()
을 호출하여 정보 창을 즉시 표시합니다.
poiMarker.showInfoWindow()
setPoiClick()
함수의 최종 코드는 다음과 같습니다.
private fun setPoiClick(map: GoogleMap) {
map.setOnPoiClickListener { poi ->
val poiMarker = map.addMarker(
MarkerOptions()
.position(poi.latLng)
.title(poi.name)
)
poiMarker.showInfoWindow()
}
}
onMapReady()
의 끝에서setPoiClick()
를 호출하고map
를 전달합니다.
override fun onMapReady(googleMap: GoogleMap) {
...
setPoiClick(map)
}
- 앱을 실행하고 공원이나 커피숍과 같은 관심 장소를 찾습니다.
- 관심 장소를 탭하여 마커를 배치하고 정보 창에 관심 장소의 이름을 표시합니다.
다양한 방법으로 Google 지도를 맞춤설정하여 지도에 고유한 디자인과 분위기를 부여할 수 있습니다.
다른 프래그먼트를 맞춤설정하는 것처럼 사용 가능한 XML 속성을 사용하여 MapFragment
객체를 맞춤설정할 수 있습니다. 하지만 이 단계에서는 GoogleMap
객체의 메서드를 사용하여 MapFragment
의 콘텐츠의 디자인을 맞춤설정합니다.
지도의 맞춤 스타일을 만들려면 지도에 표시되는 기능을 지정하는 JSON 파일을 생성합니다. 이 JSON 파일을 수동으로 만들 필요는 없습니다. Google에서는 지도의 스타일을 시각적으로 지정하면 JSON을 생성해 주는 지도 플랫폼 스타일 지정 마법사를 제공합니다. 이 작업에서는 복고풍 테마로 지도의 스타일을 지정합니다. 즉, 지도에서 빈티지 색상을 사용하고 색상이 지정된 도로를 추가합니다.
1단계: 지도 스타일 만들기
- 브라우저에서 https://mapstyle.withgoogle.com/으로 이동합니다.
- 스타일 만들기를 선택합니다.
- 레트로를 선택합니다.
- 옵션 더보기를 클릭합니다.
- 기능 유형 목록에서 도로> 채우기를 선택합니다.
- 도로 색상을 원하는 색상 (예: 분홍색)으로 변경합니다.
- 마침을 클릭합니다.
- 결과 대화상자에서 JSON 코드를 복사하고 원하는 경우 다음 단계에서 사용할 일반 텍스트 메모에 저장합니다.
2단계: 지도에 스타일 추가하기
- Android 스튜디오의
res
디렉터리에서 리소스 디렉터리를 만들고 이름을raw
로 지정합니다. JSON 코드와 같은raw
디렉터리 리소스를 사용합니다. res/raw
에map_style.json
이라는 파일을 만듭니다.- 보관된 JSON 코드를 새 리소스 파일에 붙여넣습니다.
MapsActivity
에서onCreate()
메서드 위에TAG
클래스 변수를 만듭니다. 로깅 목적으로 사용됩니다.
private val TAG = MapsActivity::class.java.simpleName
MapsActivity
에서GoogleMap
를 사용하는setMapStyle()
함수도 만듭니다.setMapStyle()
에서try{}
블록을 추가합니다.try{}
블록에서 스타일 지정이 성공하도록val success
를 만듭니다. (다음 catch 블록을 추가합니다.)try{}
블록에서 JSON 스타일을 지도에 설정하고GoogleMap
객체에서setMapStyle()
을 호출합니다. JSON 파일을 로드하는MapStyleOptions
객체를 전달합니다.- 결과를
success
에 할당합니다.setMapStyle()
메서드는 스타일 파일 파싱 및 스타일 설정의 성공 상태를 나타내는 불리언을 반환합니다.
private fun setMapStyle(map: GoogleMap) {
try {
// Customize the styling of the base map using a JSON object defined
// in a raw resource file.
val success = map.setMapStyle(
MapStyleOptions.loadRawResourceStyle(
this,
R.raw.map_style
)
)
}
}
success
가 false인 경우의 if 문을 추가합니다. 스타일 지정에 실패하면 파싱이 실패했다는 로그를 출력합니다.
private fun setMapStyle(map: GoogleMap) {
try {
...
if (!success) {
Log.e(TAG, "Style parsing failed.")
}
}
}
- 스타일 파일이 누락된 상황을 처리하는
catch{}
블록을 추가합니다.catch
블록에서 파일을 로드할 수 없는 경우Resources.NotFoundException
를 발생시킵니다.
private fun setMapStyle(map: GoogleMap) {
try {
...
} catch (e: Resources.NotFoundException) {
Log.e(TAG, "Can't find style. Error: ", e)
}
}
완성된 메서드는 다음 코드 스니펫과 같습니다.
private fun setMapStyle(map: GoogleMap) {
try {
// Customize the styling of the base map using a JSON object defined
// in a raw resource file.
val success = map.setMapStyle(
MapStyleOptions.loadRawResourceStyle(
this,
R.raw.map_style
)
)
if (!success) {
Log.e(TAG, "Style parsing failed.")
}
} catch (e: Resources.NotFoundException) {
Log.e(TAG, "Can't find style. Error: ", e)
}
}
- 마지막으로
onMapReady()
메서드에서setMapStyle()
메서드를 호출하여GoogleMap
객체를 전달합니다.
override fun onMapReady(googleMap: GoogleMap) {
...
setMapStyle(map)
}
- 앱을 실행합니다.
- 지도를
normal
모드로 설정하면 선택한 색상의 복고풍 테마와 도로가 포함된 새로운 스타일이 표시됩니다.
3단계: 마커 스타일 지정
지도 마커의 스타일을 지정하여 지도를 추가로 맞춤설정할 수 있습니다. 이 단계에서는 기본 빨간색 마커를 더 멋진 마커로 변경합니다.
onMapLongClick()
메서드에서 생성자의MarkerOptions()
에 다음 코드 줄을 추가하여 기본 마커를 사용하되 색상을 파란색으로 변경합니다.
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
이제 onMapLongClickListener()
는 다음과 같이 표시됩니다.
map.setOnMapLongClickListener { latLng ->
// A snippet is additional text that's displayed after the title.
val snippet = String.format(
Locale.getDefault(),
"Lat: %1$.5f, Long: %2$.5f",
latLng.latitude,
latLng.longitude
)
map.addMarker(
MarkerOptions()
.position(latLng)
.title(getString(R.string.dropped_pin))
.snippet(snippet)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
)
}
- 앱을 실행합니다. 이제 길게 클릭한 후 표시되는 마커가 파란색으로 음영 처리됩니다.
onPoiClick()
메서드에 스타일을 추가하지 않았으므로 POI 마커는 여전히 빨간색입니다.
Google 지도를 맞춤설정하는 한 가지 방법은 지도 위에 그리는 것입니다. 이 기법은 인기 낚시터와 같은 특정 유형의 위치를 강조하려는 경우에 유용합니다.
- 도형: 지도에 다중선, 다각형, 원을 추가할 수 있습니다.
GroundOverlay
객체: 지면 오버레이는 지도에 고정된 이미지입니다. 마커와 달리 지면 오버레이는 화면이 아닌 지표면을 기준으로 방향이 정해집니다. 지도를 회전하거나 기울이거나 확대/축소하면 이미지의 방향이 바뀝니다. 지면 오버레이는 단일 이미지를 지도의 한 영역에 고정하려는 경우에 유용합니다.
단계: 지면 오버레이 추가
이 작업에서는 Android 모양의 그라운드 오버레이를 집 위치에 추가합니다.
- 이 Android 이미지를 다운로드하고
res/drawable
폴더에 저장합니다. (파일 이름이android.png
인지 확인하세요.)
onMapReady()
에서 카메라를 홈 위치로 이동하는 호출 후GroundOverlayOptions
객체를 만듭니다.- 객체를
androidOverlay
이라는 변수에 할당합니다.
val androidOverlay = GroundOverlayOptions()
BitmapDescriptorFactory.fromResource()
메서드를 사용하여 다운로드한 이미지 리소스에서BitmapDescriptor
객체를 만듭니다.- 결과
BitmapDescriptor
객체를GroundOverlayOptions
객체의image()
메서드에 전달합니다.
val androidOverlay = GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromResource(R.drawable.android))
- 원하는 오버레이의 너비(미터)에 대한
float overlaySize
를 만듭니다. 이 예에서는 너비가100f
이면 적합합니다.
position()
메서드를 호출하여 GroundOverlayOptions
객체의 position
속성을 설정하고 homeLatLng
객체와 overlaySize
을 전달합니다.
val overlaySize = 100f
val androidOverlay = GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromResource(R.drawable.android))
.position(homeLatLng, overlaySize)
GoogleMap
객체에서addGroundOverlay()
를 호출하고GroundOverlayOptions
객체를 전달합니다.
map.addGroundOverlay(androidOverlay)
- 앱을 실행합니다.
zoomLevel
값을 18f로 변경하여 Android 이미지를 오버레이로 확인합니다.
사용자는 현재 위치를 확인하기 위해 Google 지도를 자주 사용합니다. 지도에 기기 위치를 표시하려면 위치 데이터 레이어를 사용하면 됩니다.
위치 데이터 레이어를 사용하면 지도에 내 위치가 추가됩니다. 사용자가 버튼을 탭하면 지도가 기기의 위치에 맞춰 중앙에 표시됩니다. 기기가 움직이지 않으면 위치가 파란색 점으로 표시되고 기기가 움직이면 파란색 갈매기형 아이콘으로 표시됩니다.
이 작업에서는 위치 데이터 레이어를 사용 설정합니다.
단계: 위치 정보 액세스 권한 요청
Google 지도에서 위치 추적을 사용 설정하려면 단 한 줄의 코드가 필요합니다. 하지만 사용자가 위치 권한을 부여했는지 확인해야 합니다 (런타임 권한 모델 사용).
이 단계에서는 위치 정보 액세스 권한을 요청하고 위치 추적을 사용 설정합니다.
AndroidManifest.xml
파일에서FINE_LOCATION
권한이 이미 있는지 확인합니다. Google 지도 템플릿을 선택하면 Android 스튜디오에서 이 권한을 삽입했습니다.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
MapsActivity
에서REQUEST_LOCATION_PERMISSION
클래스 변수를 만듭니다.
private val REQUEST_LOCATION_PERMISSION = 1
- 권한이 부여되었는지 확인하려면
MapsActivity
에isPermissionGranted()
이라는 메서드를 만듭니다. 이 메서드에서 사용자가 권한을 부여했는지 확인합니다.
private fun isPermissionGranted() : Boolean {
return ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
- 앱에서 위치 추적을 사용 설정하려면 인수를 사용하지 않고 아무것도 반환하지 않는
enableMyLocation()
라는 메서드를MapsActivity
에 만듭니다. 내부에서ACCESS_FINE_LOCATION
권한을 확인합니다. 권한이 부여되면 위치 레이어를 사용 설정합니다. 그 외의 경우에는 권한을 요청합니다.
private fun enableMyLocation() {
if (isPermissionGranted()) {
map.isMyLocationEnabled = true
}
else {
ActivityCompat.requestPermissions(
this,
arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_LOCATION_PERMISSION
)
}
}
onMapReady()
콜백에서enableMyLocation()
를 호출하여 위치 레이어를 사용 설정합니다.
override fun onMapReady(googleMap: GoogleMap) {
...
enableMyLocation()
}
onRequestPermissionsResult()
메서드를 재정의합니다.requestCode
이REQUEST_LOCATION_PERMISSION
과 같으면 권한이 부여되고grantResults
배열이 비어 있지 않고 첫 번째 슬롯에PackageManager.PERMISSION_GRANTED
이 있으면enableMyLocation()
를 호출합니다.
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray) {
if (requestCode == REQUEST_LOCATION_PERMISSION) {
if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
enableMyLocation()
}
}
}
- 앱을 실행합니다. 기기 위치에 대한 액세스를 요청하는 대화상자가 표시됩니다. 계속해서 권한을 허용합니다.
이제 지도에 파란색 점을 사용하여 기기의 현재 위치가 표시됩니다. 위치 버튼이 있습니다. 내 위치에서 지도를 멀리 이동한 후 이 버튼을 클릭하면 지도가 기기의 위치로 다시 중앙에 배치됩니다.
완료된 Codelab의 코드를 다운로드합니다.
$ git clone https://github.com/googlecodelabs/android-kotlin-geo-maps
또는 ZIP 파일로 저장소를 다운로드한 다음 압축을 풀고 Android 스튜디오에서 열어도 됩니다.
- Maps API를 사용하려면 Google API 콘솔의 API 키가 필요합니다.
- Android 스튜디오에서 Google 지도 활동 템플릿을 사용하면 앱 레이아웃에 단일
SupportMapFragment
이 있는Activity
이 생성됩니다. 템플릿은 앱 매니페스트에ACCESS_FINE_PERMISSION
도 추가하고, 활동에서OnMapReadyCallback
를 구현하고, 필수onMapReady()
메서드를 재정의합니다.
런타임에 GoogleMap
의 지도 유형을 변경하려면 GoogleMap.setMapType()
메서드를 사용합니다. Google 지도는 다음 지도 유형 중 하나일 수 있습니다.
- 일반: 일반적인 도로 지도입니다. 도로, 인공 지형지물, 주요 자연 지형지물(예: 강)을 표시합니다. 도로 및 지점 라벨도 표시됩니다.
- 하이브리드: 도로 지도가 추가된 위성 사진 데이터입니다. 도로 및 지점 라벨도 표시됩니다.
- 위성: 사진 데이터입니다. 도로 및 지형지물 라벨은 표시되지 않습니다.
- 지형: 지형 데이터입니다. 지도에 색상, 등고선, 라벨, 원근감을 나타내는 명암이 포함됩니다. 도로 및 라벨도 일부 표시됩니다.
- 없음: 기본 지도 타일이 없습니다.
Google 지도에 대한 정보:
- 마커는 특정 지리적 위치를 나타내는 표시기입니다.
- 탭하면 마커의 기본 동작은 위치에 관한 정보가 포함된 정보 창을 표시하는 것입니다.
- 기본적으로, 관심 지점(POI)은 해당 아이콘과 함께 기본 지도에 나타납니다. 관심 장소에는 공원, 학교, 정부 건물 등이 포함됩니다.
- 또한 지도 유형이
normal
인 경우 비즈니스 관심 장소 (상점, 음식점, 호텔 등)가 지도에 기본적으로 표시됩니다. OnPoiClickListener
를 사용하여 관심 장소의 클릭을 캡처할 수 있습니다.- 스타일 마법사를 사용하면 Google 지도의 거의 모든 요소의 시각적 모양을 변경할 수 있습니다. 스타일 지정 마법사는
setMapStyle()
메서드를 사용하여 Google 지도에 전달하는 JSON 파일을 생성합니다. - 기본 색상을 변경하거나 기본 마커 아이콘을 맞춤 이미지로 교체하여 마커를 맞춤설정할 수 있습니다.
기타 중요 정보:
- 지면 오버레이를 사용하여 이미지를 지리적 위치에 고정합니다.
GroundOverlayOptions
객체를 사용하여 이미지, 이미지의 크기(미터), 이미지의 위치를 지정합니다. 이 객체를GoogleMap.addGroundOverlay()
메서드에 전달하여 오버레이를 지도에 설정합니다.- 앱에
ACCESS_FINE_LOCATION
권한이 있는 경우map.isMyLocationEnabled = true
을 설정하여 위치 추적을 사용 설정할 수 있습니다. - 이 Codelab에서는 다루지 않지만 특정 위치의 탐색 가능한 파노라마 사진인 Google 스트리트 뷰를 사용하여 위치에 관한 추가 정보를 제공할 수 있습니다.
Android 개발자 문서:
참조 문서
이 과정의 다른 Codelab 링크는 Kotlin 기반 Android 고급 Codelab 방문 페이지를 참고하세요.