๐Ÿ“Œ  ๊ตฌ๊ธ€ ํ”Œ๋ ˆ์ด ์„œ๋น„์Šค์˜ Google Maps API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ตฌ๊ธ€ ์ง€๋„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์•ฑ์— ์ง€๋„๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Œ

      -  ๊ตฌ๊ธ€ ์ง€๋„๋Š” Google Maps Platform ์„œ๋น„์Šค ์ค‘์˜ ํ•˜๋‚˜์ด๋ฉฐ, ๊ตํ†ต์ •๋ณด ๊ธฐ๋ฐ˜์˜ ๊ฒฝ๋กœ ์ฐพ๊ธฐ์™€ ์žฅ์†Œ ์ •๋ณด, ๊ฒ€์ƒ‰ ๋“ฑ์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณต.
      -  ๊ตญ๋‚ด์—์„œ๋Š” ๊ตฌ๊ธ€ ์ง€๋„์˜ ๊ฒฝ๋กœ์ฐพ๊ธฐ ๋ฉ”๋‰ด์ค‘ ๋ฒ„์Šค๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ.

 

1.  ๊ตฌ๊ธ€ ์ง€๋„ ์‹œ์ž‘ํ•˜๊ธฐ

 

 

์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค๋Š” ๊ตฌ๊ธ€ ์ง€๋„๋ฅผ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ์‹œ ํ”„๋กœ์ ํŠธ์˜ ์ข…๋ฅ˜๋ฅผ ์„ ํƒํ•˜๋Š” ๋ฉ”๋‰ด์—์„œ Google Maps Activity๋ฅผ ์ œ๊ณต

 

  โžก๏ธ  MainActivity ๋Œ€์‹  MapsActivity๊ฐ€ ์ƒ์„ฑ๋จ

 

 

 

 

 

 

 

Google Maps API ํ‚ค ์„ค์ •


๊ตฌ๊ธ€ ์ง€๋„๋ฅผ ํฌํ•จํ•œ ๊ตฌ๊ธ€ ํ”Œ๋ ˆ์ด ์„œ๋น„์Šค์— ์—‘์„ธ์Šคํ•˜๋ ค๋ฉด ๊ตฌ๊ธ€ ํ”Œ๋ ˆ์ด ์„œ๋น„์Šค์˜ API ํ‚ค๊ฐ€ ํ•„์š”
์ด์ „์—๋Š” google_maps_api.xml ํŒŒ์ผ์ด ์ž๋™ ์ƒ์„ฑ๋˜๊ณ , ํ•ด๋‹น ํŒŒ์ผ์— APIํ‚ค๋ฅผ ์ž…๋ ฅํ–ˆ์œผ๋‚˜, ๋ฒ”๋ธ”๋น„์™€ ์นฉ๋ฉํฌ ๋ฒ„์ „ ๋ถ€ํ„ฐ๋Š” AndroidManifest.xml์— APIํ‚ค๋ฅผ ์ž…๋ ฅํ•˜๋„๋ก ๋ณ€๊ฒฝ์ด ๋จ

<!--
    TODO: Before you run your application, you need a Google Maps API key.

    To get one, follow the directions here:

    https://developers.google.com/maps/documentation/android-sdk/get-api-key

    Once you have your API key (it starts with "AIza"), define a new property in your
    project's local.properties file (e.g. MAPS_API_KEY=Aiza...), and replace the
    "YOUR_API_KEY" string in this file with "${MAPS_API_KEY}".
-->
    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="YOUR_API_KEY" />

 

 

ํ‚ค๋ฅผ ์ž…๋ ฅ ํ›„์— ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค์—์„œ ์•ฑ์„ ๋นŒ๋“œํ•˜๊ณ  ์‹œ์ž‘ํ•˜๋ฉด, ์‹œ๋“œ๋‹ˆ์— ๋งˆ์ปค๊ฐ€ ํ‘œ์‹œ๋œ ์ง€๋„๋ฅผ ํ‘œ์‹œ

 

  ๐Ÿ“ ์ง€๋„๊ฐ€ ์•ˆ ๋œจ๋ฉด ๊ตฌ๊ธ€ cloud ์ ‘์† ํ•˜์—ฌ API key ์ˆ˜์ •์—์„œ ํŒจํ‚ค์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋จ !  โ–ถ๏ธ ํŒจํ‚ค์ง€๋ช…์€ ๋ฌด์กฐ๊ฑด ์†Œ๋ฌธ์ž !!

 

 


2.  ๊ตฌ๊ธ€ ์ง€๋„ ์ฝ”๋“œ ์‚ดํŽด๋ณด๊ธฐ

activity_maps.xml์˜ SupportMapFragment

 

ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด activity_maps.xml ํŒŒ์ผ์ด ์ž๋™ ์ƒ์„ฑ๋จ. ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด android:name์— "com.google.android.gms.maps.SupportMapFragment"๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ์Œ.

Google Maps API๋Š” SupportMapFragment์— ๊ตฌ๊ธ€ ์ง€๋„๋ฅผ ํ‘œ์‹œ.

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res-auto"
    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=".MapsActivity" />

 

 

MapsActivity.kt์˜ SupportMapFragment.getMapAsync
 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMapsBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        val mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)
    }

 

MapsActivity.kt ํŒŒ์ผ์„ ์—ด๋ฉด onCreate() ๋ฉ”์„œ๋“œ ๋ธ”๋ก ์•ˆ์—์„œ๋Š” supportFragmentManager์˜ findFragmentById() ๋ฉ”์„œ๋“œ๋กœ id๊ฐ€ map์ธ SupportMapFragment๋ฅผ ์ฐพ์€ ํ›„ getMapAsync()๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์•ˆ๋“œ๋กœ์ด๋“œ์— ๊ตฌ๊ธ€ ์ง€๋„๋ฅผ ๊ทธ๋ ค๋‹ฌ๋ผ๋Š” ์š”์ฒญ์„ ํ•จ.

 

MapsActivity.kt์˜ OnMapReadyCallback

 

class MapsActivity : AppCompatActivity(), OnMapReadyCallback { }

 

์•ˆ๋“œ๋กœ์ด๋“œ๋Š” ๊ตฌ๊ธ€ ์ง€๋„๊ฐ€ ์ค€๋น„๋˜๋ฉด OnMapReadyCallback ์ธํ„ฐํŽ˜์ด์Šค์˜ onMapReady() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ค€๋น„๋œ GoogleMap์„ ์ „๋‹ฌํ•ด ์คŒ.

override fun onMapReady(googleMap: GoogleMap) {
        mMap = googleMap

        // Add a marker in Sydney and move the camera
        val sydney = LatLng(-34.0, 151.0)
        mMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
        mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
    }

 

๋ฉ”์„œ๋“œ ์•ˆ์—์„œ ๋ฏธ๋ฆฌ ์„ ์–ธ๋œ mMap ํ”„๋กœํผํ‹ฐ์— GoogleMap์„ ์ €์žฅํ•ด๋‘๋ฉด ์•กํ‹ฐ๋น„ํ‹ฐ ์ „์ฒด์—์„œ ๋งต์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ.
๊ตฌ๊ธ€์—์„œ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ์‹œ๋“œ๋‹ˆ์˜ ์ขŒํ‘œ ์ฝ”๋“œ๊ฐ€ ์žˆ์Œ.

 

* API Level 12 ์ดํ•˜ ๋ฒ„์ „์—์„œ์˜ ํ˜ธํ™˜์„ฑ์ด ํ•„์š”์—†๋‹ค๋ฉด SupportMapFragment ๋Œ€์‹  MapFragment๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ.
* ์Šค๋งˆํŠธํฐ์— ๊ตฌ๊ธ€ ํ”Œ๋ ˆ์ด ์„œ๋น„์Šค๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ๊ตฌ๊ธ€ ํ”Œ๋ ˆ์ด ์„œ๋น„์Šค๋ฅผ ์„ค์น˜ํ•  ๋•Œ๊นŒ์ง€ onMapReady() ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Œ.

 


3.  ์นด๋ฉ”๋ผ์™€ ์ง€๋„ ๋ทฐ

๊ตฌ๊ธ€ ์ง€๋„์—์„œ๋Š” ์นด๋ฉ”๋ผ๋ฅผ ํ†ตํ•ด ํ˜„์žฌ ํ™”๋ฉด์˜ ์ง€๋„ ๋ทฐ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Œ.
  โœ“  ์ง€๋„ ๋ทฐ๋Š” ํ‰๋ฉด์—์„œ ์•„๋ž˜๋ฅผ ๋‚ด๋ ค๋‹ค ๋ณด๋ฉด์„œ ๋ชจ๋ธ๋ง ๋˜๋ฉฐ ์นด๋ฉ”๋ผ์˜ ํฌ์ง€์…˜์€ ์œ„๋„/๊ฒฝ๋„, ๋ฐฉ์œ„, ๊ธฐ์šธ๊ธฐ ๋ฐ ํ™•๋Œ€/์ถ•์†Œ ์†์„ฑ์œผ๋กœ ์ง€์ •
  โœ“  ์นด๋ฉ”๋ผ์˜ ์œ„์น˜๋Š” CameraPosition ํด๋ž˜์Šค์— ๊ฐ์ข… ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด์„œ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ์Œ

CameraPosition.Builder().์˜ต์…˜1.์˜ต์…˜2.build()

Target


  โœ“  ์นด๋ฉ”๋ผ์˜ ๋ชฉํ‘œ ์ง€์  Target์€ ์ง€๋„ ์ค‘์‹ฌ์˜ ์œ„์น˜์ด๋ฉฐ ์œ„๋„ ๋ฐ ๊ฒฝ๋„ ์ขŒํ‘œ๋กœ ์ง€์ •

CameraPosition.Builder().target(LatLng(-34.0, 151.0))

 


Zoom

 

  โœ“  ์นด๋ฉ”๋ผ์˜ ์คŒ Zoom (ํ™•๋Œ€/์ถ•์†Œ) ๋ ˆ๋ฒจ์— ๋”ฐ๋ผ ์ง€๋„์˜ ๋ฐฐ์œจ์ด ๊ฒฐ์ •. ์คŒ ๋ ˆ๋ฒจ์ด ๋†’์„ ์ˆ˜๋ก ๋” ์ž์„ธํ•œ ์ง€๋„๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๋ฐ˜๋ฉด, ์คŒ ๋ ˆ๋ฒจ์ด ์ž‘์„์ˆ˜๋ก ๋” ๋„“์€ ์ง€๋„๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Œ.

CameraPosition.Builder().zoom(15.5f)

 

 

๐Ÿ“  ์คŒ ๋ ˆ๋ฒจ์ด 0์ธ ์ง€๋„์˜ ๋ฐฐ์œจ์€ ์ „ ์„ธ๊ณ„์˜ ๋„ˆ๋น„๊ฐ€ ์•ฝ 256dp๊ฐ€ ๋˜๋ฉฐ ๋ ˆ๋ฒจ์˜ ๋ฒ”์œ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Œ

๋ ˆ๋ฒจ ์„ค๋ช…
1.0 ์„ธ๊ณ„
5.0 ๋Œ€๋ฅ™
10.0 ๋„์‹œ
15.0 ๊ฑฐ๋ฆฌ
20.0 ๊ฑด๋ฌผ

 


Bearing


  โœ“  ์นด๋ฉ”๋ผ์˜ ๋ฒ ์–ด๋ง Bearing์€ ์ง€๋„์˜ ์ˆ˜์ง์„ ์ด ๋ถ์ชฝ์„ ๊ธฐ์ค€์œผ๋กœ ์‹œ๊ณ„ ๋ฐฉํ–ฅ ๋‹จ์œ„๋กœ ์ธก์ •๋˜๋Š” ๋ฐฉํ–ฅ.

CameraPosition.Builder().bearing(300f)

Tilt


  โœ“  ์นด๋ฉ”๋ผ์˜ ๊ธฐ์šธ๊ธฐ Tilt๋Š” ์ง€๋„์˜ ์ค‘์•™ ์œ„์น˜์™€ ์ง€๊ตฌ ํ‘œ๋ฉด ์‚ฌ์ด์˜ ์›ํ˜ธ์—์„œ ์นด๋ฉ”๋ผ ์œ„์น˜๋ฅผ ์ง€์ •
  โœ“  ๊ธฐ์šธ๊ธฐ๋กœ ์‹œ์•ผ๊ฐ์„ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ฉ€๋ฆฌ ๋–จ์–ด์ง„ ์ง€ํ˜•์ด ๋” ์ž‘๊ฒŒ ๋‚˜ํƒ€๋‚˜๊ณ  ์ฃผ๋ณ€ ์ง€ํ˜•์ด ๋” ์ผœ์ ธ ๋งต์ด ์›๊ทผ์œผ๋กœ ๋‚˜ํƒ€๋‚จ

CameraPosition.Builder().tilt(50f)

 


4.  ์†Œ์Šค ์ฝ”๋“œ์—์„œ ์นด๋ฉ”๋ผ ์ด๋™ํ•˜๊ธฐ

์˜ต์…˜์„ ์ด์šฉํ•ด์„œ CameraPosition ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  moveCamera() ๋ฉ”์„œ๋“œ๋กœ ์นด๋ฉ”๋ผ์˜ ์œ„์น˜๋ฅผ ์ด๋™์‹œ์ผœ ์ง€๋„์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Œ.
  โžก๏ธ  MapsActivity.kt ํŒŒ์ผ์˜ onMapReady() ๋ฉ”์„œ๋“œ ์•ˆ์— ์ž‘์„ฑ.

CameraPosition.Builder ๊ฐ์ฒด๋กœ ์นด๋ฉ”๋ผ ํฌ์ง€์…˜์„ ์„ค์ •


  ๐Ÿ“  build() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ CameraPosition ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ

val cameraPosition = CameraPosition.Builder()
    .target(LATLNG)
    .zoom(15.0f)
    .build()

 

CameraUpdateFactory.newCameraPosition() ๋ฉ”์„œ๋“œ์— CameraPosition ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ์นด๋ฉ”๋ผ ํฌ์ง€์…˜์— ์ง€๋„์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์นด๋ฉ”๋ผ ์ •๋ณด๊ฐ€ ์ƒ์„ฑ
val cameraUpdate =
    CameraUpdateFactory.newCameraPosition(cameraPosition)

 

๋ณ€๊ฒฝ๋œ ์นด๋ฉ”๋ผ ์ •๋ณด๋ฅผ GoogleMap์˜ () ๋ฉ”์„œ๋“œ์— ์ „๋‹ฌํ•˜๋ฉด ์นด๋ฉ”๋ผ ํฌ์ง€์…˜์„๊ธฐ์ค€์œผ๋กœ ์ง€๋„์˜ ์œ„์น˜, ๋ฐฐ์œจ, ๊ธฐ์šธ๊ธฐ ๋“ฑ์ด ๋ณ€๊ฒฝ๋˜์–ด ํ‘œ์‹œ
mMap.moveCamera(cameraUpdate)

 


5.  ๋งˆ์ปค

๋งˆ์ปค Marker๋Š” ์ง€๋„์— ์œ„์น˜๋ฅผ ํ‘œ์‹œ. ์•„์ด์ฝ˜์˜ ์ƒ‰์ƒ, ์ด๋ฏธ์ง€, ์œ„์น˜๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋Œ€ํ™”์‹์œผ๋กœ ์„ค๊ณ„๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋งˆ์ปค๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ •๋ณด์ฐฝ์„ ๋„์šฐ๊ฑฐ๋‚˜ ํด๋ฆญ๋ฆฌ์Šค๋„ˆ์ฒ˜๋Ÿผ ํด๋ฆญ์— ๋Œ€ํ•œ ์ฝ”๋“œ ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ์Œ.

 

๋งˆ์ปค ํ‘œ์‹œํ•˜๊ธฐ

 

  1. mMap = googleMap ์ฝ”๋“œ ์•„๋ž˜์— ํŠน์ • ์žฅ์†Œ์˜ ์œ„๋„์™€ ๊ฒฝ๋„ ์ขŒํ‘œ๊ฐ’์œผ๋กœ LatLng ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ

val LATLNG = LatLng(35.8715, 128.6017)

 

  2.  ๋งˆ์ปค๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ๋งˆ์ปค์˜ ์˜ต์…˜์„ ์ •์˜ํ•œ MarkerOptions ๊ฐ์ฒด๊ฐ€ ํ•„์š”.

        MarkerOptions ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋จธ์ปค์˜ ์ขŒํ‘œ์™€ ์ œ๋ชฉ์„ ์„ค์ •.

val markerOptions = MarkerOptions()
    .position(LATLNG)
    .title("Marker")

 

  3. GoogleMap ๊ฐ์ฒด์˜ addMarker() ๋ฉ”์„œ๋“œ์— MarkerOptions๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ๊ตฌ๊ธ€ ์ง€๋„์— ๋งˆ์ปค๊ฐ€ ์ถ”๊ฐ€.

mMap.addMarker(markerOptions)

 

  4. ์นด๋ฉ”๋ผ๋ฅผ ๋งˆ์ปค์˜ ์ขŒํ‘œ๋กœ ์ด๋™ํ•˜๊ณ  ์คŒ์„ ๊ฑฐ๋ฆฌ ๋ ˆ๋ฒจ๋กœ ํ™•๋Œ€

val cameraPosition = CameraPosition.Builder()
    .target(LATLNG)
    .zoom(15.0f)
    .build()

val cameraUpdate =
    CameraUpdateFactory.newCameraPosition(cameraPosition)
    mMap.moveCamera(cameraUpdate)

 

  5. MarkerOptions ๊ฐ์ฒด์˜ title(), snippet() ๋ฉ”์„œ๋“œ๋กœ ์ •๋ณด ์ฐฝ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋งˆ์ปค๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ •๋ณด์ฐฝ์ด ํ‘œ์‹œ

val markerOptions = MarkerOptions()
    .position(LATLNG)
    .title("Daegu City Hall")
    .snippet("35.8715, 128.6017")

 

 

๋งˆ์ปค ์•„์ด์ฝ˜ ๋ณ€๊ฒฝํ•˜๊ธฐ

 

๋งˆ์ปค ์•„์ด์ฝ˜์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณต๋˜๋Š” ์•„์ด์ฝ˜๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋น„ํŠธ๋งต ์ด๋ฏธ์ง€๋กœ ๋ณ€๊ฒฝํ• ์ˆ˜ ์žˆ์Œ.
PNG ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€ํ•˜๊ณ  ๋น„ํŠธ๋งต์œผ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์•„์ด์ฝ˜์œผ๋กœ ๋ณ€๊ฒฝ.

 

  1. drawable ๋””๋ ‰ํ† ๋ฆฌ์— ๋งˆ์ปค ์•„์ด์ฝ˜์œผ๋กœ ์ ์šฉํ•  PNG ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์ถ”๊ฐ€

  2. onMapReady() ์•ˆ์— ์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€

val bitmapDrawable: BitmapDrawable

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    bitmapDrawable = getDrawable(R.drawable.marker) as BitmapDrawable
} else {
    bitmapDrawable = resources.getDrawable(R.drawable.marker) as BitmapDrawable
}

 

  3. BitmapDescriptorFactory.fromBitmap() ๋ฉ”์„œ๋“œ์— BitmapDrawable์˜ ๋น„ํŠธ๋งต ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋งˆ์ปค ์•„์ด์ฝ˜์„ ์œ„ํ•œ
BitmapDescriptor ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  import

var discriptor =
    BitmapDescriptorFactory.fromBitmap(bitmapDrawable.bitmap)

 

  4. MarkerOptions ๊ฐ์ฒด์˜ icon() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ BitmapDescriptor ๊ฐ์ฒด์˜ ์•„์ด์ฝ˜์„ ๋งˆ์ปค์— ์ ์šฉํ•˜๋„๋ก ์ˆ˜์ •

val markerOptions = MarkerOptions()
    .position(LATLNG)
    .icon(discriptor)
mMap.addMarker(markerOptions)

 

  * ์•„์ด์ฝ˜์˜ ํฌ๊ธฐ๊ฐ€ ํด ๊ฒฝ์šฐ Bitmap.createScaledBitmap() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ ํฌ๊ธฐ๋ฅผ ์ค„์ธ ๋น„ํŠธ๋งต ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜๋ฐ›์•„์•ผ ํ•จ

 


6.  ํ˜„์žฌ ์œ„์น˜ ๊ฒ€์ƒ‰ํ•˜๊ธฐ

์Šค๋งˆํŠธํฐ์ฒ˜๋Ÿผ ๋ชจ๋ฐ”์ผ ํ™˜๊ฒฝ์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์œ„์น˜๋ฅผ ์ด๋™ํ•˜๊ณ  ๊ทธ ์œ„์น˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœํ•˜๋Š” ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Œ.
  โœ“  ์•ฑ์—์„œ ์Šค๋งˆํŠธํฐ์˜ ํ˜„์žฌ ์œ„์น˜๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ ค๋ฉด ์œ„์น˜ ๊ถŒํ•œ์ด ํ•„์š”
  โœ“  ์•ˆ๋“œ๋กœ์ด๋“œ ํ”Œ๋žซํผ์€ ํ˜„์žฌ ์œ„์น˜๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” FusedLocationProviderClinet API๋ฅผ ์ œ๊ณต
        โžก๏ธ  FusedLocationProviderClinet API๋Š” GPS Global Positioning System ์‹ ํ˜ธ ๋ฐ ์™€์ดํŒŒ์ด์™€ ํ†ต์‹ ์‚ฌ ๋„คํŠธ์›Œํฌ ์œ„์น˜๋ฅผ ๊ฒฐํ•ฉํ•ด์„œ ์ตœ์†Œํ•œ์˜ ๋ฐฐํ„ฐ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์œผ๋กœ ๋น ๋ฅด๊ณ  ์ •ํ™•ํ•˜๊ฒŒ ์œ„์น˜๋ฅผ ๊ฒ€์ƒ‰

 

Google Play Service ์˜์กด์„ฑ ์ถ”๊ฐ€ํ•˜๊ธฐ


  FusedLocationProviderClinet API๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ build.gradle ํŒŒ์ผ์— ๊ตฌ๊ธ€ ํ”Œ๋ ˆ์ด ์„œ๋น„์Šค์˜ Loacation ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€. Location ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” Maps ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๋ฒ„์ „์ด ๊ฐ™์•„์•ผ ํ•จ. Location ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๊ฐ™์•„์ง€๋„๋ก Maps์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „์„ ๋งž์ถฐ์คŒ.

implementation 'com.google.android.gms:play-services-location:18.2.0'
implementation 'com.google.android.gms:play-services-maps:18.2.0'

 

๊ถŒํ•œ์„ ๋ช…์„ธํ•˜๊ณ  ์š”์ฒญ/ ์ฒ˜๋ฆฌํ•˜๊ธฐ

 

  ์Šค๋งˆํŠธํฐ์˜ ์œ„์น˜ ๊ธฐ๋Šฅ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด AndroidManifest.xml ํŒŒ์ผ์— ์œ„์น˜ ๊ถŒํ•œ์„ ์„ ์–ธ. ์œ„์น˜ ๊ถŒํ•œ์€ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ์œผ๋ฉฐ ๊ธฐ๋Šฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Œ.

<!-- ๋„์‹œ ๋ธ”๋ก ๋‚ด์—์„œ ์ •ํ™•ํ•œ ์œ„์น˜ (๋„คํŠธ์›Œํฌ ์œ„์น˜) -->
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- ์ •ํ™•ํ•œ ์œ„์น˜ ํ™•๋ณด (๋„คํŠธ์›Œํฌ ์œ„์น˜ + GPS ์œ„์น˜) -->
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"/>

 

  MapsActivity์— OnMapReadyCallback ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์† ๋ฐ›์Œ.

class MapsActivity : AppCompatActivity(), OnMapReadyCallback {}

 

  ๊ถŒํ•œ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด์„œ onCreate() ๋ฉ”์„œ๋“œ ์œ„์— ๋Ÿฐ์ฒ˜๋ฅผ ์„ ์–ธ. ์—ฌ๊ธฐ์„œ๋Š” ํ•œ ๋ฒˆ์— 2๊ฐœ์˜ ๊ถŒํ•œ์— ๋Œ€ํ•œ ์Šน์ธ์„ ์š”์ฒญํ•˜๊ธฐ ๋•Œ๋ฌธ์— Contract๋กœ RequestMultiplePermissions()๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•จ. ๋”ฐ๋ผ์„œ ๋Ÿฐ์ฒ˜์˜ ์ œ๋„ค๋ฆญ์€ ๋ฌธ์ž์—ด ๋ฐฐ์—ด์ธ <Array<String>>์ด ๋จ

lateinit var locationPermission: ActivityResultLauncher<Array<String>>

 

  onCreate() ๋ฉ”์„œ๋“œ ์•„๋ž˜์— ๋นˆ startProcess() ๋ฉ”์„œ๋“œ๋ฅผ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด ๋‘ . 

fun startProcess() {
    // ์Šน์ธ ํ›„ ์‹คํ–‰ํ•  ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅ
}

 

  onCreate() ๋ฉ”์„œ๋“œ ์•ˆ์— ๋Ÿฐ์ฒ˜๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์•ž์—์„œ ์„ ์–ธํ•ด ๋‘” ๋ณ€์ˆ˜์— ์ €์žฅ.

locationPermission =
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { 
        results -> if (results.all{ it.value }) {
                       startProcess()
                   } else {
                       Toast.makeText(this, "๊ถŒํ•œ ์Šน์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.",
                       Toast.LENGTH_LONG).show()
                   }
    }

 

  ๋ฐ”๋กœ ์•„๋ž˜์ค„์— ๋Ÿฐ์ฒ˜๋ฅผ ์‹คํ–‰ํ•ด์„œ ๊ถŒํ•œ ์Šน์ธ์„ ์š”์ฒญ. 2๊ฐœ์˜ ๊ถŒํ•œ์„ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ „๋‹ฌํ•ด์•ผ๋˜๊ธฐ ๋•Œ๋ฌธ์— arrayOf()๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ถŒํ•œ 2๊ฐœ๋ฅผ ๊ฐ™์ด launch()์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ž…๋ ฅ.

locationPermission.launch(arrayOf(
    Manifest.permission.ACCESS_COARSE_LOCATION,
    Manifest.permission.ACCESS_FINE_LOCATION
))

 

  ์œ„์น˜ ๊ถŒํ•œ์ด ์Šน์ธ๋˜๋ฉด startProcess() ๋ฉ”์„œ๋“œ์—์„œ ๊ตฌ๊ธ€ ์ง€๋„๋ฅผ ์ค€๋น„ํ•˜๋Š” ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •. onCreate()์— ์ž‘์„ฑ๋˜์–ด ์žˆ๋Š” val mapFragment ๋กœ ์‹œ์ž‘ํ•˜๋Š” ์„ธ ์ค„์„ ์ž˜๋ผ๋‚ด๊ธฐ ํ•œ ํ›„ startProcess() ๋ฉ”์„œ๋“œ ์•ˆ์— ๋ถ™์—ฌ๋„ฃ๊ธฐ ํ•˜๋ฉด ๋จ.

fun startProcess() {
    // ์Šน์ธ ํ›„ ์‹คํ–‰ํ•  ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅ
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    val mapFragment = supportFragmentManager
        .findFragmentById(R.id.map) as SupportMapFragment
         mapFragment.getMapAsync(this)
}

 

  ์ด์ œ ๊ถŒํ•œ์ด ๋ชจ๋‘ ์Šน์ธ๋˜๊ณ  ๋งต์ด ์ค€๋น„๋˜๋ฉด onMapReady() ๋ฉ”์„œ๋“œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ํ˜ธ์ถœ.

 


ํ˜„์žฌ ์œ„์น˜ ๊ฒ€์ƒ‰ํ•˜๊ธฐ

 

 1. onCreate() ์œ„์— onMapReady() ์œ„์น˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ณ€์ˆ˜ 2๊ฐœ๋ฅผ ์„ ์–ธ
     โœ“  fusedLocationClient๋Š” ์œ„์น˜๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ•„์š”ํ•˜๊ณ , locationCallback์€ ์œ„์นซ๊ฐ’ ์š”์ฒญ์— ๋Œ€ํ•œ ๊ฐฑ์‹  ์ •๋ณด๋ฅผ ๋ฐ›๋Š” ๋ฐ ํ•„์š”

private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationCallback: LocationCallback

 

 2. onMapReady() ์•ˆ์˜ ์‹œ๋“œ๋‹ˆ ์ขŒํ‘œ ์ฝ”๋“œ๋ฅผ ์‚ญ์ œํ•œ ๋‹ค์Œ, ์œ„์น˜ ๊ฒ€์ƒ‰ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  updateLocation() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ

override fun onMapReady(googleMap: GoogleMap) {
    mMap = googleMap
    fusedLocationClient =
        LocationServices.getFusedLocationProviderClient(this)
    updateLocation()
}

 

 3. updateLocation() ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑ.

  • ์œ„์น˜ ์ •๋ณด๋ฅผ ์š”์ฒญํ•  ์ •ํ™•๋„์™€ ์ฃผ๊ธฐ๋ฅผ ์„ค์ •ํ•  locationRequest๋ฅผ ๋จผ์ € ์ƒ์„ฑํ•˜๊ณ , ํ•ด๋‹น ์ฃผ๊ธฐ๋งˆ๋‹ค ๋ฐ˜ํ™˜๋ฐ›์„ locationCallback์„ ์ƒ์„ฑ
  • onMapReady์—์„œ ์ƒ์„ฑํ•œ ์œ„์น˜ ๊ฒ€์ƒ‰ ํด๋ผ์ด์–ธํŠธ์˜ requestLocationUpdates()์— ์•ž์—์„œ ์ƒ์„ฑํ•œ 2๊ฐœ์™€ ๋ฃจํผ ์ •๋ณด๋ฅผ ๋„˜๊ฒจ์คŒ
  • ์ด์ œ 1์ดˆ(1,000๋ฐ€๋ฆฌ์ดˆ)์— ํ•œ ๋ฒˆ์”ฉ ๋ณ€ํ™”๋œ ์œ„์น˜์ •๋ณด๊ฐ€ LocationCallback์˜ onLocationResult()๋กœ ์ „๋‹ฌ์ด ๋จ.
  • onLocationResult()๋Š” ๋ฐ˜ํ™˜๋ฐ›์€ ์ •๋ณด์—์„œ ์œ„์น˜ ์ •๋ณด๋ฅผ setLastLoation()์œผ๋กœ ์ „๋‹ฌ.
  • fusedLocationClient.requestLocationUpdates ์ฝ”๋“œ๋Š” ๊ถŒํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ๋ฐ ํ˜„์žฌ ์ฝ”๋“œ์—์„œ๋Š” ํ™•์ธํ•  ์ˆ˜ ์—†์Œ.
  • ๋”ฐ๋ผ์„œ ๋ฉ”์„œ๋“œ ์ƒ๋‹จ์— ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์ฒดํฌํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค๋Š” ์˜๋ฏธ๋กœ @SuppressLint("MissingPermission") ์• ๋„ˆํ…Œ์ด์…˜์„ ๋‹ฌ์•„์คŒ.
@SuppressLint("MissingPermission")
fun updateLocation() {
    val locationRequest = LocationRequest.create()
    locationRequest.run {
        priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        interval = 1000
    }

locationCallback = object: LocationCallback() {
    override fun onLocationResult(locationResult: LocationResult?) {
        locationResult?.let {
            for ((i, location) in it.locations.withIndex()) {
                Log.d("Location", "$i ${location.latitude}, ${location.longitude}")
                setLastLoation(location)
            }
        }
    }
}

fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())

 

 

4. updateLocation() ๋ฉ”์„œ๋“œ ์•„๋ž˜์— ์œ„์น˜ ์ •๋ณด๋ฅผ ๋ฐ›์•„์„œ ๋งˆ์ปค๋ฅผ ๊ทธ๋ฆฌ๊ณ  ํ™”๋ฉด์„ ์ด๋™ํ•˜๋Š” setLastLoation()์„ ์ž‘์„ฑ

fun setLastLoation(lastLocatin: Location) { }

 

5. ์ „๋‹ฌ๋ฐ›์€ ์œ„์น˜ ์ •๋ณด๋กœ ์ขŒํ‘œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ•ด๋‹น ์ขŒํ‘œ๋กœ ๋งˆ์ปค๋ฅผ ์ƒ์„ฑ

fun setLastLoation(lastLocatin: Location) {
    val LATLNG = LatLng(lastLocatin.latitude, lastLocatin.longitude)
    val markerOptions =
        MarkerOptions().position(LATLNG).title("Here!")
}

 

6. ์นด๋ฉ”๋ผ ์œ„์น˜๋ฅผ ํ˜„์žฌ ์œ„์น˜๋กœ ์„ธํŒ…ํ•˜๊ณ  ๋งˆ์ปค์— ํ•จ๊ป˜ ์ง€๋„์— ๋ฐ˜์˜.

    โœ“  ๋งˆ์ปค๋ฅผ ์ง€๋„์— ๋ฐ˜์˜ํ•˜๊ธฐ ์ „์— mMap.clear()๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์ด์ „์— ๊ทธ๋ ค์ง„ ๋งˆ์ปค๊ฐ€์žˆ์œผ๋ฉด ์ง€์›€

fun setLastLoation(lastLocatin: Location) {
    val LATLNG = LatLng(lastLocatin.latitude, lastLocatin.longitude)
    val markerOptions =
        MarkerOptions().position(LATLNG).title("Here!")

    val cameraPosition =
        CameraPosition.Builder().target(LATLNG).zoom(15.0f).build() 
    mMap.clear()
    mMap.addMarker(markerOptions)

    mMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)
}

 

 

 

 

[ ๋‚ด์šฉ ์ฐธ๊ณ  : IT ํ•™์› ๊ฐ•์˜ ]

 

+ Recent posts