데이터를 이용한 다중 Marker를 찍고 마커가 많을 시
GoogleMap이 지저분 하지 않기 위해 클러스터를 통해 마커를 모아주기
GoogleMap API 사용과 기본 마커 찍기
코로나 진료소 API를 찔러 위도, 경도를 받고 다중 마커를 찍었는데 마커가 많아 가독성을 흐려 클러스터링을 사용하고 싶어 구현해보았다.
Clustering
클러스터링을 구현하려면 ClusterItem을 구현해줘야 한다.
따로 마커 Class를 관리해도 되지만 데이터를 받자마자 클러스터를 찍고 싶어 API Data Class에 바로 ClusterItem을 사용하였다.
ClusterItem을 Data Class에 상속하면 필수 Override 옵션이 필요하다.
getPosition(): LatLng | 마커를 찍을 위도 경도 반환 |
getTitle(): String | 마커 Title 반환 |
getSnippet(): String | 마커 Snippet 반환 |
@Xml(name = "item")
data class HospItem(
@PropertyElement(name = "addr") //주소
var addr: String,
@PropertyElement(name = "recuClCd") //요양종별코드 //11:종합병원 21:병원 31:의원
var recuClCd: String,
...
@PropertyElement(name = "yadmNm") //기관명
var yadmNm: String,
@PropertyElement(name = "YPosWgs84") //위도
var YPosWgs84: Double,
@PropertyElement(name = "XPosWgs84") //경도
var XPosWgs84: Double,
): ClusterItem {
override fun getPosition(): LatLng {
return LatLng(YPosWgs84, XPosWgs84)
}
override fun getTitle(): String {
return yadmNm
}
override fun getSnippet(): String {
return addr
}
}
API에서 위도, 경도, 타이틀, 스니펫을 바로 받아와 바로 return 해주었다.
(DataClass가 클러스터 마커의 역할을 한다 생각하면 됨)
Cluster를 사용하기 위해 만들어준 ClusterItem을 가지는 ClusterManager 객체를 선언.
private lateinit var clusterManager: ClusterManager<HospItem>
이후 onMapReady()안에서 GoogleMap과 연동해야 한다.
class MapsFragment : BaseFragment<FragmentMapBinding>(R.layout.fragment_map), OnMapReadyCallback {
...
private lateinit var mGoogleMap: GoogleMap
private lateinit var clusterManager: ClusterManager<HospItem>
var dataList = listOf<HospItem>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
...
binding.mapView.getMapAsync(this)
getHospData() //병원 Data를 가져와 dataList에 넣어줌
}
override fun onMapReady(googleMap: GoogleMap) {
subscribe(this)
val seoul = LatLng(37.554891, 126.970814)
mGoogleMap = googleMap
//클러스터 매니저 구글맵과 연동
clusterManager = ClusterManager(mContext, mGoogleMap)
mGoogleMap.setOnCameraIdleListener(clusterManager)
mGoogleMap.setOnMarkerClickListener(clusterManager)
dataList.forEachIndexed { index, hospMarker ->
clusterManager.addItem(hospMarker)
}
}
}
클러스터를 사용하면 기본 마커가 적용되는데 이를 변경하고 싶으면 ClusterLender를 적용해 Cluster를 Custom 해주어야 한다.
Custom Cluster
dependencies {
...
implementation 'com.google.maps.android:android-maps-utils:2.2.3'
}
DefaultClusterRenderer<만든 ClusterItem>를 상속하는 Custom Cluster 클래스 생성
override 되는 onBeforeClusterItemRendered() 메소드 안에서 Item안의 Data 값으로 지정해줄 마커 Icon을 분기
(ClusterItem을 통신으로 받아오는 DataClass로 만들어 받아온 통신 데이터 값으로 구분해서 Icon을 구분하였지만 필요에 의하면 따로 ClustItem을 만드는 것을 권장)
class CustomMarker(private val context: Context, map: GoogleMap, clusterManager: ClusterManager<HospItem>)
: DefaultClusterRenderer<HospItem>(context, map, clusterManager) {
override fun onBeforeClusterItemRendered(item: HospItem, markerOptions: MarkerOptions) {
val id: Int = when(item.recuClCd){
//받아온 Data 값으로 지정해줄 Icon 분기
MapRepository.HOSP_COMPREHENSIVE -> R.drawable.ic_hosp_comprehensive
MapRepository.HOSP_GENERAL -> R.drawable.ic_hosp_general
MapRepository.HOSP_DOCTOR_OFFICE -> R.drawable.ic_host_doctor_office
else -> R.drawable.ic_hosp_comprehensive
}
//Drawable 불러와 Bitmap으로 변환
val drawable = ContextCompat.getDrawable(context, id)
val markerIcon: BitmapDescriptor = CanvasUtil.drawableToBitmapDescriptor(drawable!!)
//MarkerOptions에 set
markerOptions.icon(markerIcon)
markerOptions.snippet(item.snippet)
markerOptions.title(item.title)
super.onBeforeClusterItemRendered(item, markerOptions)
}
}
이렇게 만든 CustomCluster를 onMapReady()에서 Cluster객체를 생성할때 사용
override fun onMapReady(googleMap: GoogleMap) {
subscribe(this)
mGoogleMap = googleMap
clusterManager = ClusterManager(mContext, mGoogleMap)
//CustomCluster 사용
clusterManager.renderer = CustomMarker(mContext, mGoogleMap, clusterManager)
dataList.forEachIndexed { index, hospMarker ->
clusterManager.addItem(hospMarker)
}
}
Marker Clustering
https://developers.google.com/maps/documentation/android-sdk/utility/marker-clustering?hl=ko
https://medium.com/geekculture/walk-through-google-map-platform-101-in-android-7c72a4dd40e3
'Android > Library' 카테고리의 다른 글
Ktor (0) | 2023.12.03 |
---|---|
Fresco (0) | 2022.03.31 |
GeoCoding 위도 경도 <-> 주소 변환하기 (4) | 2022.02.20 |
Google Map API 사용 방법 및 예제 (0) | 2022.02.18 |
Epoxy, Epoxy에 Databinding 사용 (RecyclerView 쉽게 사용) (0) | 2022.02.14 |