Android - Google Map API 설치부터 심화 활용까지 (커스텀 마커) (2) (Kotlin)

업데이트:

  • 연구주제 : Android - Google Map 활용 (Kotlin)
  • 연구목적 : 안드로이드에서의 코틀린 활용
  • 연구일시 : 2020년 04월 07일 09:00~17:00
  • 연구자 : 이재환 ljh951103@naver.com
  • 연구장비 : HP EliteDesk 800 G4 TWR, Kotlin, Android studio, IntelliJ
  • 관련연구 : Java, Android, Kotlin, Google, API


서론

이번 시간에는 커스텀 마커를 이용해서 구글 맵을 활용해 보겠다.

image

위와 같이, 마커를 여러개 찍고, 일반적인 구글 맵 마커들의 테마를 변경해보자.

https://gun0912.tistory.com/57

포스팅을 기준으로 작성되었으므로 참고해도 좋다.


본론

우선 저번 포스팅의 내용을 따라왔다면 이제는 구글 맵 API를 활용할 수 있게 되었다.


1. 이미지 준비

우선 커스텀 마커를 이용하기 위해 이미지를 받아야한다.
이미지는 나인패치 이미지를 이용해야하는데 위의 링크 블로그에 있는 이미지를 사용해도 좋고 개인 이미지를 사용해도 좋다.

이 이미지는 링크 블로그에 포함된 나인패치 이미지이다.

image image


2. 마커 레이아웃 작성

이미지를 성공적으로 옮겼다면 마커 레이아웃을 작성한다.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >

    <TextView
        android:id="@+id/tag_marker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:background="@drawable/ic_marker_phone"
        android:gravity="center"
        android:textSize="16sp" />
</FrameLayout>


3. 마커에 사용할 데이터 클래스 생성

마커에 사용하기 위한 데이터 클래스를 작성한다.
각자 서비스에 맞게 작성하면 된다.

class LatLngData(
    val id : Long,
    val latlng: LatLng,
    val tag: String) {
}


4. 샘플 마커 데이터 생성

샘플로 테스트 하기 위한 데이터를 생성해준다.
그리고 마커를 추가할 수 있게 해준다.

var latlngdata = arrayListOf<LatLngData>()

latlngdata.add(LatLngData(1, LatLng(35.162339, 129.108509), "가"))
latlngdata.add(LatLngData(2, LatLng(35.224836, 129.088285), "나"))
latlngdata.add(LatLngData(3, LatLng(35.080117, 129.048376), "다"))

for (i in latlngdata.indices) {
    addMarker(latlngdata[i], false)
    }


5. 마커 추가 함수 정의

우선 커스텀 마커를 적용하기위한 xml을 가져온다.

private fun setCustomMarkerView() {
        marker_view = LayoutInflater.from(this).inflate(R.layout.marker_layout, null)
        tag_marker = marker_view.findViewById(R.id.tag_marker) as TextView
    }


그리고 실제 마커를 추가하는 addMarker() 함수를 만들어준다.

private fun addMarker(latlngdata: LatLngData, isSelectedMarker:Boolean): Marker{
        var list: List<Address>? = null
        var markerOptions = MarkerOptions()
            if (isSelectedMarker) {
                tag_marker.setBackgroundResource(R.drawable.ic_marker_phone_blue)
                tag_marker.setTextColor(Color.WHITE)
            } else {
                tag_marker.setBackgroundResource(R.drawable.ic_marker_phone)
                tag_marker.setTextColor(Color.BLACK)
            }

            markerOptions.position(latlngdata.latlng)
            tag_marker.setText(latlngdata.tag)
            markerOptions.icon(
                        BitmapDescriptorFactory.fromBitmap(createDrawableFromView(this, marker_view
                    )
                )
            )
            return mMap.addMarker(markerOptions)
    }


이제 마커뷰를 비트맵으로 변환해주는 작업이 필요하다.

private fun createDrawableFromView(context: Context, view: View): Bitmap {
        val displayMetrics = DisplayMetrics()
        (context as Activity).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics)
        view.setLayoutParams(
            ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
            )
        )
        view.measure(displayMetrics.widthPixels, displayMetrics.heightPixels)
        view.layout(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels)
        view.buildDrawingCache()
        val bitmap: Bitmap = Bitmap.createBitmap(
            view.getMeasuredWidth(),
            view.getMeasuredHeight(),
            Bitmap.Config.ARGB_8888
        )
        val canvas = Canvas(bitmap)
        view.draw(canvas)
        return bitmap
    }


5. 마커 클릭 리스너 정의

이제 코드를 돌려보면 마커가 변환되어 지도에 표시되는 것을 확인할 수 있다.

하지만 아직 한 가지 할 일이 더 있다.
마커를 선택했을 때, 카메라 변화와 마커 테마가 변하도록 해야한다.

클릭 리스너에 대한 정의는 다음과 같이 해준다.
즉, 마커가 클릭되면 카메라를 이동시키고 마커 이미지를 변경한다.

mMap.setOnMarkerClickListener(object: GoogleMap.OnMarkerClickListener {
            override fun onMarkerClick(marker: Marker): Boolean {
                val center: CameraUpdate = CameraUpdateFactory.newLatLng(marker.getPosition())
                mMap.animateCamera(center)
                changeSelectedMarker(marker)
                return true
            }
        })


마커를 되돌리는 함수를 정의한다.
selectMarker에 선택된 마커를 저장하여 조건 분기를 통해 마커를 조정한다.

 private fun changeSelectedMarker(marker: Marker?) {
        // 선택했던 마커 되돌리기
        if(selectedMarker != marker) {
            if (selectedMarker != null) {
                addMarker(selectedMarker!!, false)
                selectedMarker!!.remove()
            }

            // 선택한 마커 표시
            if (marker != null) {
                addMarker(marker, true)
                marker.remove()
            }
            else
                selectedMarker = null
        }
    }


맵을 클릭했을 땐 선택된 마커를 제거해줘야 한다.

mMap.setOnMapClickListener (object: GoogleMap.OnMapClickListener{
            override fun onMapClick(p0: LatLng?) {
                changeSelectedMarker(null);
            }
        })


그리고 마지막으로 마커를 다시 생성하기 위한 별도의 addMarker() 함수를 만들어준다.

private fun addMarker(marker: Marker, isSelectedMarker: Boolean): Marker {
    val lat: Double = marker.getPosition().latitude
    val lon: Double = marker.getPosition().longitude
    val tag: String = marker.getTitle()
    val temp = MarkerItem(lat, lon, price)
    return addMarker(temp, isSelectedMarker)
}

이제 실행시켜보면 제대로 적용되어 다음 사진처럼 출력된다.

image


결론

커스텀마커를 구글 맵에서 사용해보았다.
하지만 이렇게만 구현하게되면 마커가 굉장히 많을 경우, 마커가 겹쳐서 구분하기 힘들다.
따라서 다음 포스팅에선 이 문제를 해결할 수 있는 클러스터링 기능을 사용해보자.


향후과제

구글 맵 클러스터링 활용


참고자료

https://gun0912.tistory.com/57


Writer: Jae-Hwan Lee

댓글남기기