본문 바로가기
안드로이드스튜디오 개발

[안드로이드 스튜디오] 네이버 지도 #5 - 정보창(InfoWindow) 표시하기

by jinu957 2020. 6. 15.
728x90

 

이번 포스트에서는 네이버 지도에 InfoWindow 즉, 정보창을 표시하는 방법에 대해 설명하도록 하겠습니다.

 

지난 번 마커를 표시하는 예제에 InfoWindow를 표시할 예정이니 기본이 되는 프로젝트는 아래 글을 참조하시기 바랍니다.

 

2020/06/15 - [안드로이드스튜디오 개발] - [안드로이드 스튜디오] 네이버지도 #4 - 마커 표시 및 이벤트처리

 

[안드로이드 스튜디오] 네이버지도 #4 - 마커 표시 및 이벤트처리

이번 포스팅에서는 네이버 지도에 마커를 표시하는 방법을 설명하도록 하겠습니다. 이전 포스팅에서 만들었던 프로젝트를 활용하여 계속 코딩합니다. 2020/06/15 - [안드로이드스튜디오 개발] - [��

andro-jinu.tistory.com

 

네이버의 InfoWindow는 지도상에 간단한 정보창을 표출하는 것으로 특정한 위치(위경도) 또는 마커 위에 표시할 수 있습니다.

 

이번 포스팅에서는 

1) 임의의 좌표(위도, 경도)에 정보창 표시하기

2) 특정 마커 위에 정보창 표시하기

3) 마커 클릭 시 정보창 표시하기

4) 정보창 클릭 시 이벤트 처리하기

입니다.

 

 

먼저 테스트를 위하여 activity_main.xml 에 몇개의 버튼을 추가합니다.

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/btnmark1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="마커1"/>
        <Button
            android:id="@+id/btnmark2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="마커2"/>
        <Button
            android:id="@+id/btninfo1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="정보창1"/>
        <Button
            android:id="@+id/btninfo2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="정보창2"/>
    </LinearLayout>

    <com.naver.maps.map.MapView
        android:id="@+id/map_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

기존에 btnmark3은 삭제하였고 btninfo1, btninfo2 버튼을 추가하였습니다.

 

btnmark1, btnmark2는 각각 마커를 생성하는데 사용되고

btninfo1은 임의의 좌표에  정보창을 표시하고

btninfo2는 btnmark1버튼이 생성한 마커 위에 정보창을 표시할겁니다.

그리고 btnmark2 버튼이 생성한 마커를 클릭하면 그 마커위에 정보창을 생성합니다.

 

그럼 먼저 btninfo1 버튼이 클릭됐을때 임의의 좌표에 정보창을 표시하는 소스입니다.

btnInfo1.setOnClickListener(new Button.OnClickListener()
{
    @Override
    public void onClick(View v)
    {
        infoWindow1.setAdapter(new InfoWindow.DefaultTextAdapter(getApplication())
        {
            @NonNull
            @Override
            public CharSequence getText(@NonNull InfoWindow infoWindow)
            {
                return "정보창1";
            }
        });

        //인포창의 우선순위
        infoWindow1.setZIndex(10);
        //투명도 조정
        infoWindow1.setAlpha(0.9f);
        //위치 지정
        infoWindow1.setPosition(new LatLng(33.28, 126.4));
        //인포창 표시
        infoWindow1.open(naverMap);
    }
});

 

정보창의 내용을 표시하기 위해서는 .setAdapter를 사용합니다.

사용할 수 있는 어댑터의 종류는

 

InfoWindow.DefaultTextAdapter
InfoWindow.DefaultViewAdapter
InfoWindow.Adapter
InfoWindow.ViewAdapter

 

이렇게 4가지가 있으며 이번 예제에서는 간단한 텍스트를 표시할 예정이기 때문에 

InfoWindow.DefaultTextAdapter를 사용합니다. (좀 더 다양하게 디자인하는 방법은 다음 포스팅에서 설명하도록하겠습니다.)

 

위 소스에서는 getText() 함수의 리턴값으로 "정보창1" 을 반환하도록 하였습니다.

 

나머지 정보창 설정하는 방법은 마커랑 비슷합니다. 

 

여기서는 임의의 좌표에 표시하기위하여 setPosition함수를 사용하여 위경도값을 지정하고 open함수를 사용하여 지도상에 표시합니다.

infoWindow1.open(naverMap);

단, 임의의 좌표를 사용하기 때문에 open함수 안에는 네이버지도 객체를 넣어줍니다.

 

정보창을 닫을 때는 close를 사용합니다.

infoWindow1.close();

 

다음은 btnInfo2를 클릭했을때 첫번째 마커 위에 정보창을 표시하고 정보창을 클릭했을때 토스트메시지를 표출하는 소스입니다.

btnInfo2.setOnClickListener(new Button.OnClickListener()
{
    @Override
    public void onClick(View v)
    {
        infoWindow2.setAdapter(new InfoWindow.DefaultTextAdapter(getApplication())
        {
            @NonNull
            @Override
            public CharSequence getText(@NonNull InfoWindow infoWindow)
            {
                return "마커1위에 표시";
            }
        });

        //인포창의 우선순위
        infoWindow2.setZIndex(10);
        //투명도 조정
        infoWindow2.setAlpha(0.9f);
        //인포창 표시
        infoWindow2.open(marker1);

        infoWindow2.setOnClickListener(new Overlay.OnClickListener()
        {
            @Override
            public boolean onClick(@NonNull Overlay overlay)
            {
                Toast.makeText(MainActivity.this, "정보창2 클릭됨", Toast.LENGTH_SHORT).show();
                return false;
            }
        });
    }
});

 

임의의 좌표에 표시할때는 setPosition 함수로 위치를 지정하고 open함수에 지도객체를 넣어줬는데 

마커위에 표시할때는 그냥 open함수에 마커 객체만 넣어 주면 됩니다.

 

그리고 클릭이벤트 처리에서는

infoWindow2.setOnClickListener(new InfoWindow.OnClickListener() 이 아니라

infoWindow2.setOnClickListener(new Overlay.OnClickListener()으로 하는것만 주의하시면 됩니다.

 

다음은 마커를 클릭했을때 정보창을 표시하는 소스입니다.

btnMark2.setOnClickListener(new Button.OnClickListener()
{
    @Override
    public void onClick(View v)
    {
        setMarker(marker2, 33.49957, 126.531076, R.drawable.ic_album_black_24dp, 10);

        marker2.setOnClickListener(new Overlay.OnClickListener()
        {
            @Override
            public boolean onClick(@NonNull Overlay overlay)
            {
                infoWindow3.setAdapter(new InfoWindow.DefaultTextAdapter(getApplication())
                {
                    @NonNull
                    @Override
                    public CharSequence getText(@NonNull InfoWindow infoWindow)
                    {
                        return "제주도청";
                    }
                });

                //인포창의 우선순위
                infoWindow3.setZIndex(10);
                //투명도 조정
                infoWindow3.setAlpha(0.9f);
                //인포창 표시
                infoWindow3.open(marker2);
                return false;
            }
        });
    }
});

 

위에서 설명한 것말고 특별한건 없습니다.

 

 

그럼 이제 전체 MainActivity 소스입니다.

 

package com.test.navermap;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import com.naver.maps.geometry.LatLng;
import com.naver.maps.map.CameraPosition;
import com.naver.maps.map.MapView;
import com.naver.maps.map.NaverMap;
import com.naver.maps.map.OnMapReadyCallback;
import com.naver.maps.map.overlay.InfoWindow;
import com.naver.maps.map.overlay.Marker;
import com.naver.maps.map.overlay.Overlay;
import com.naver.maps.map.overlay.OverlayImage;

public class MainActivity extends AppCompatActivity implements OnMapReadyCallback
{

    private MapView mapView;
    private static NaverMap naverMap;

    //마커 변수 선언 및 초기화
    private Marker marker1 = new Marker();
    private Marker marker2 = new Marker();

    //Infowindow 변수 선언 및 초기화
    private InfoWindow infoWindow1 = new InfoWindow();
    private InfoWindow infoWindow2 = new InfoWindow();
    private InfoWindow infoWindow3 = new InfoWindow();

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btnMark1 = (Button) findViewById(R.id.btnmark1);
        Button btnMark2 = (Button) findViewById(R.id.btnmark2);
        Button btnInfo1 = (Button) findViewById(R.id.btninfo1);
        Button btnInfo2 = (Button) findViewById(R.id.btninfo2);

        btnMark1.setOnClickListener(new Button.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                setMarker(marker1, 33.2712, 126.5354, R.drawable.ic_place_black_24dp, 0);

                marker1.setOnClickListener(new Overlay.OnClickListener()
                {
                    @Override
                    public boolean onClick(@NonNull Overlay overlay)
                    {
                        Toast.makeText(getApplication(), "마커1 클릭", Toast.LENGTH_SHORT).show();
                        return false;
                    }
                });
            }
        });

btnMark2.setOnClickListener(new Button.OnClickListener()
{
    @Override
    public void onClick(View v)
    {
        setMarker(marker2, 33.49957, 126.531076, R.drawable.ic_album_black_24dp, 10);

        marker2.setOnClickListener(new Overlay.OnClickListener()
        {
            @Override
            public boolean onClick(@NonNull Overlay overlay)
            {
                infoWindow3.setAdapter(new InfoWindow.DefaultTextAdapter(getApplication())
                {
                    @NonNull
                    @Override
                    public CharSequence getText(@NonNull InfoWindow infoWindow)
                    {
                        return "제주도청";
                    }
                });

                //인포창의 우선순위
                infoWindow3.setZIndex(10);
                //투명도 조정
                infoWindow3.setAlpha(0.9f);
                //인포창 표시
                infoWindow3.open(marker2);
                return false;
            }
        });
    }
});

        btnInfo1.setOnClickListener(new Button.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                infoWindow1.setAdapter(new InfoWindow.DefaultTextAdapter(getApplication())
                {
                    @NonNull
                    @Override
                    public CharSequence getText(@NonNull InfoWindow infoWindow)
                    {
                        return "정보창1";
                    }
                });

                //인포창의 우선순위
                infoWindow1.setZIndex(10);
                //투명도 조정
                infoWindow1.setAlpha(0.9f);
                //위치 지정
                infoWindow1.setPosition(new LatLng(33.28, 126.4));
                //인포창 표시
                infoWindow1.open(naverMap);
            }
        });

        btnInfo2.setOnClickListener(new Button.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                infoWindow2.setAdapter(new InfoWindow.DefaultTextAdapter(getApplication())
                {
                    @NonNull
                    @Override
                    public CharSequence getText(@NonNull InfoWindow infoWindow)
                    {
                        return "마커1위에 표시";
                    }
                });

                //인포창의 우선순위
                infoWindow2.setZIndex(10);
                //투명도 조정
                infoWindow2.setAlpha(0.9f);
                //인포창 표시
                infoWindow2.open(marker1);

                infoWindow2.setOnClickListener(new Overlay.OnClickListener()
                {
                    @Override
                    public boolean onClick(@NonNull Overlay overlay)
                    {
                        Toast.makeText(MainActivity.this, "정보창2 클릭됨", Toast.LENGTH_SHORT).show();
                        return false;
                    }
                });
            }
        });

        //네이버 지도
        mapView = (MapView) findViewById(R.id.map_view);
        mapView.onCreate(savedInstanceState);
        mapView.getMapAsync(this);
    }

    private void setMarker(Marker marker,  double lat, double lng, int resourceID, int zIndex)
    {
        //원근감 표시
        marker.setIconPerspectiveEnabled(true);
        //아이콘 지정
        marker.setIcon(OverlayImage.fromResource(resourceID));
        //마커의 투명도
        marker.setAlpha(0.8f);
        //마커 위치
        marker.setPosition(new LatLng(lat, lng));
        //마커 우선순위
        marker.setZIndex(zIndex);
        //마커 표시
        marker.setMap(naverMap);
    }

    private void setInfoWindow(InfoWindow infoWindow,  double lat, double lng, int resourceID, int zIndex)
    {
    }

    @Override
    public void onMapReady(@NonNull NaverMap naverMap)
    {
        this.naverMap = naverMap;

        //배경 지도 선택
        naverMap.setMapType(NaverMap.MapType.Navi);

        //건물 표시
        naverMap.setLayerGroupEnabled(naverMap.LAYER_GROUP_BUILDING, true);

        //위치 및 각도 조정
        CameraPosition cameraPosition = new CameraPosition(
                new LatLng(33.38, 126.55),   // 위치 지정
                9,                                     // 줌 레벨
                45,                                       // 기울임 각도
                0                                     // 방향
        );
        naverMap.setCameraPosition(cameraPosition);
    }

    @Override
    public void onStart()
    {
        super.onStart();
        mapView.onStart();
    }

    @Override
    public void onResume()
    {
        super.onResume();
        mapView.onResume();
    }

    @Override
    public void onPause()
    {
        super.onPause();
        mapView.onPause();
    }

    @Override
    public void onStop()
    {
        super.onStop();
        mapView.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mapView.onDestroy();
    }

    @Override
    public void onSaveInstanceState(Bundle outState)
    {
        super.onSaveInstanceState(outState);
        mapView.onSaveInstanceState(outState);
    }

    @Override
    public void onLowMemory()
    {
        super.onLowMemory();
        mapView.onLowMemory();
    }
}

 

이제 실행해보시면 

1) 마커1 표시

2) 마커2 표시

3) 임의의 좌표에 정보창 표시

4) 마커위에 정보창 표시

5) 마커2 클릭 시 정보창 표시

6) 정보창 클릭 시 토스트메시지 표출하기

등이 잘 되는걸 볼 수 있습니다.

 

 

 

그럼 다음 포스팅에서는 단순한 텍스트의 정보창이 아닌 디자인된 뷰를 표시하기 위해서 InfoWindow.DefaultViewAdapter 를 사용하는 방법을 설명하도록 하겠습니다.

 

 

PS. 매번 프로젝트만 진행하다가 개인적으로 앱을 하나 출시했습니다.

비록 허접한 앱이기는 하지만 이걸 토대로 몇몇가지 팁에 대해 포스팅을 작성하려고 하오니 아래 포스팅 글 한번 읽어봐 주시면 감사하겠습니다. ^^

andro-jinu.tistory.com/entry/todaysaying1

 

[안드로이드 스튜디오] 앱 출시 소식 - 오늘의 명언(명언, 고사성어, 속담)

아주 오랜만에 포스팅을 하게 됐네요 그동안 다른 프로젝트로 매우 바뻤던 관계로 한동안 포스팅을 못했는데 요즘 짬이 나서 간단하게 앱을 만들고 출시까지 하였습니다. 그동안은 앱을 만들긴

andro-jinu.tistory.com

 

728x90

댓글