본문 바로가기
개발/안드로이드

[안드로이드] 구글맵 + 마커 클러스터링 + 커스텀 마커 + 마커 클릭 이벤트 구현

by 핸디(Handy) 2020. 1. 15.

제가 진행중인 프로젝트에서 카카오맵 -> 구글맵으로 전환하기로 결정을 했습니다.

다시 구현해보면서 다른점과 어떤 방식으로 구현했는지 기록하고자 글을 적습니다.

Map_kickboard 에서 구글맵을 fragment에 가져와 하나의 클래스에서 하나의 지도에 대한 기능을 구현하고자 했습니다.

 

노란색 칠한 것만 implements 에 넣는다.

Listener 설명 
 1. GoogleMap.OnCameraIdleListener -> 구글맵에서 맵이동이 끝났을 때 호출되는 리스너입니다.
 2. ClusterManager.OnClusterItemClickListener<Cluster_item> -> 이건 이름 그대로 클러스터링 아이템을 클릭했을때 호출되는 리스너입니다. 커스텀마커의 클릭 이벤트를 만들기 위해서 구현했습니다. <Cluster_item>은 클러스터링에 들어갈 마커의 item입니다. 아래의 그림과 같이 implemets에 ClusterItem을 해주시면 됩니다. 

public class Cluster_item implements ClusterItem {
    private final LatLng mPosition;
    public String device_code;
    public int brand_tag;
    public String device_battery;


    public  Cluster_item(double lat, double lng, String device_code, String device_battery,int brand_tag){
        mPosition = new LatLng(lat, lng);
        this.brand_tag = brand_tag;
        this.device_code = device_code;
        this.device_battery = device_battery;
    }
    @Override
    public LatLng getPosition() {
        return mPosition;
    }

    @Override
    public String getTitle() {
        return null;
    }

    @Override
    public String getSnippet() {
        return null;
    }

    public int getBrand_tag() {
        return brand_tag;
    }

    public String getDevice_code() {
        return device_code;
    }

    public String getDevice_battery() {
        return device_battery;
    }
}

*카카오맵과 다르게 구글맵은 onCreate 이후에 맵이 로딩되는 onMapReady(GoogleMap map)이 별도로 존재합니다. 그래서 맵에 관련된 기능들을 이 안에다 구현할 수 있어서 나름 편했습니다. 카카오맵에서는 맵 로딩이 끝나기전에 함수를 호출하게 되는 상황을 피하기 위해 콜백을 따로 구현했어야 했는데 구글맵에는 있습니다.

 

   //마커 클러스터링 준비
        mClusterManager = new ClusterManager<>(this, mMap);
        mClusterManager.setRenderer(new MarkerRenderer(getApplicationContext(),mMap,mClusterManager));
        mClusterManager.setOnClusterItemClickListener(this);
 //리스너 달아주기
        mMap.setOnCameraIdleListener(mClusterManager);
        mMap.setOnMarkerClickListener(mClusterManager);

저기 보이는 mClusterManager.setRenderer 은 클러스터링되는 마커를 커스텀하기 위해 필요한 것입니다. 다양한 것을 랜더링(커스텀) 할 수 있습니다.

  private class MarkerRenderer extends DefaultClusterRenderer<Cluster_item>{
        public MarkerRenderer(Context context, GoogleMap map, ClusterManager<Cluster_item> clusterManager) {
            super(context, map, clusterManager);
        }

        @Override
        public void onClustersChanged(Set<? extends Cluster<Cluster_item>> clusters) {
            super.onClustersChanged(clusters);
            onCameraIdle();
        }

        @Override
        protected void onBeforeClusterItemRendered(Cluster_item item, MarkerOptions markerOptions) {
            super.onBeforeClusterItemRendered(item, markerOptions);
            switch (item.getBrand_tag()){
                case 21:{
                    markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_swing));
                    break;
                }
                case 23:{
                    markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_flower));
                    break;
                }
                case 24:{
                    markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_xingxing));
                    break;
                }
                case 25:{
                    markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_kickgoing));
                    break;
                }
                case 26:{
                    markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_gogosing));
                    break;
                }
                default:{
                    //markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_xingxing));
                    break;
                }
            }

        }

        @Override
        public void setOnClusterItemClickListener(ClusterManager.OnClusterItemClickListener<Cluster_item> listener) {
            super.setOnClusterItemClickListener(listener);
        }
    }

onBeforeClusterItemRendered <- 요 함수가 이름 그대로, 클러스터링 하기전에 아이템을 랜더링 하는 것입니다.
저는 커스텀 마커를 만들기 위해서 기존에 Cluster_item의 속성으로 있던 Brand_tag를 가지고 마커 이미지를 변경해주었습니다.

그 결과 브랜드에 따라서 각각의 마커를 커스텀하고 클러스터링을 합쳐서 할 수 있게 되었습니다.

 

@Override
    public boolean onClusterItemClick(Cluster_item cluster_item) {
        Toast.makeText(this, cluster_item.getBrand_tag() + " " + cluster_item.getPosition(), Toast.LENGTH_SHORT).show();
        switch (cluster_item.getBrand_tag()){
            case 21:{
                SwingDetailApi swingDetailApi = new SwingDetailApi();
                swingDetailApi.execute(cluster_item.device_code);
                Intent intent = new Intent(Map_kickboard.this, MarkerActivity_swing.class);
                startActivityForResult(intent, 1);

                break;
            }
            case 23:{
                MarkerActivity_flower.marker_flower_code = cluster_item.getDevice_code();
                MarkerActivity_flower.marker_flower_battery = cluster_item.getDevice_battery();
                Intent intent = new Intent(Map_kickboard.this, MarkerActivity_flower.class);
                startActivityForResult(intent, 1);
                break;
            }
            case 24:{
                MarkerActivity_xing.marker_xing_code = cluster_item.getDevice_code();
                MarkerActivity_xing.marker_xing_battery = cluster_item.getDevice_battery();
                Intent intent = new Intent(Map_kickboard.this, MarkerActivity_xing.class);
                startActivityForResult(intent, 1);
                break;
            }
            case 25:{
                MarkerActivity_kickgo.marker_kickgo_code  = cluster_item.getDevice_code();
                MarkerActivity_kickgo.marker_kickgo_battery = cluster_item.getDevice_battery();
                Intent intent = new Intent(Map_kickboard.this, MarkerActivity_kickgo.class);
                startActivityForResult(intent, 1);
                break;
            }
            case 26:{
                MarkerActivity_gogo.marker_gogosing_code = cluster_item.getDevice_code();
                MarkerActivity_gogo.marker_gogosing_battery = cluster_item.getDevice_battery();
                Intent intent = new Intent(Map_kickboard.this, MarkerActivity_gogo.class);
                startActivityForResult(intent, 1);
                break;
            }
            default:{
                //markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_xingxing));
                break;
            }
        }
        return true;
    }

onClusterItemClick <- 마커 아이템을 클릭했을때 호출됩니다. 여기서 각각의 브랜드에 맞는 마커의 이벤트를 구현할 수 있었습니다.

마지막으로 마커 클릭 이벤트를 만들어 다이얼로그 액티비티와 좌표 토스 메시지를 띄워보았습니다.

설명 글 읽어주셔서 감사합니다. 혹여 틀린 내용, 부족한 것이 있으면 항상 감사히 조언 듣겠습니다.

댓글