티스토리 뷰

* 이번에는 저번의 GPS 위치 가져오기 이후에 지도 위에 말풍선을 띄우는 것을 한번 공부해보자.


- 이전 글 목록

2012/11/05 - [Android(안드로이드) 앱 개발 기초] Eclipse 개발환경 설정하기, Android SDK 설치하기

2012/11/07 - [Android(안드로이드) 앱 개발 기초] 안드로이드 프로젝트 생성하고 에뮬레이터로 앱 실행하기

2012/11/10 - [Android(안드로이드) 앱 개발 기초] 간단한 인터페이스 구현과 다른 Activity로 넘어가기

2012/11/21 - [Android(안드로이드) 앱 개발 기초] Activity 라이프사이클 공부

2012/11/24 - [Android(안드로이드) 앱 개발 응용] Google Map API로 지도 보여주기(MapView), Overlay Item 그려주기 예제

2012/11/28 - [Android(안드로이드) 앱 개발 응용] Location GPS 위치 가져오기 및 최적화

2012/12/05 - [Android(안드로이드) 앱 개발 기초] 런타임 설정(로테이션, orientation) 변환 라이프사이클



* 지난번에 이어서

:일단 지난번에 Google Map API로 지도 보여주는 것 이후에 이어서 말풍선을 그려보는 것을 해보자. 저번의 상태에 이어서 지도에 말풍선을 그려보자.


2012/11/24 - [Android(안드로이드) 앱 개발 응용] Google Map API로 지도 보여주기(MapView), Overlay Item 그려주기 예제



: 지난번에는 지도 위의 특정 위치에 마커를 그렸다면, 이번에는 마크 말고 여러 가지 정보들을 넣을 말 풍선을 넣어보자. 말풍선을 저번처럼 OverlayItem으로 넣을수도 있지만, OverlayItem은 여러개가 있을 때 관리하기 편할 것 같고, 지금 구현하려는 말풍선은 한번에 하나만 띄우는 말풍선으로 다른 쉬운 방법으로 MapView위에 SubView를 넣어주는 방법으로 한번 해보자.


* Layout 구성하기

: 먼저 말풍선의 Layout을 그려주는 xml 파일을 작성하자. Layout은 차후에 LayoutInflater를 이용해서 Layout을 extend하는 사용자 클래스로 설정을 할 것이기 때문에 제일 위의 태그는 해당하는 클래스명을 넣고 설정해주자. 여기서는 unikys.icu.ICUMapBalloon을 확장할 것이고, 일단은 간단하게 TextView하나에 데이터를 보여주는 것으로 한다.


<unikys.icu.ICUMapBalloon xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/transparent_panel"
    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingLeft="5dp" >

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/close_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:clickable="true"
            android:contentDescription="@string/close"
            android:scaleX="0.5"
            android:scaleY="0.5"
            android:src="@android:drawable/ic_menu_close_clear_cancel" />

        <TextView
            android:id="@+id/note_label"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:text="@string/note" />
        
    </RelativeLayout>

    <TextView
        android:id="@+id/note_text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:maxLength="160"
        android:maxLines="4"
        android:minLines="4"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        android:text="@string/unikys_tistory_com"
        android:textSize="5pt" />

</unikys.icu.ICUMapBalloon>



: 위의 @string/note와 @string/unikys_tistory_com은 res/value/string.xml에 적당한 값을 선택하여 세팅하거나 똑같이 해도 된다. Graphical Layout으로 한번 확인해보면, unikys.icu.ICUMapBalloon이 없다고 경고를 띄운다.



: 그럼 해당하는 클래스를 만들어주자. 예제에서는 unikys.icu.ICUMapBalloon 클래스를 만들어주자.



: 그리고 위처럼 해당 클래스가 android.widget.LinearLayout을 확장하게 하자. 위의 Superclass에 위처럼 쓰거나, 오른쪽의 Browse를 누르면 아래와 같은 윈도우가 열리는데 이 때 LinearLayout으로 검색하면 바로 나온다. LinearLayout을 선택해서 OK 를 누르고 Finish를 눌러서 생성하자.



* MapBalloon 클래스 구현하기

: MapBalloon 클래스는 위에서 정의해놓은 xml 레이아웃을 불러와서 설정할 클래스로 Layout에서는 나타나지 않은 기본 배경, 물풍선 테두리를 그려 넣게 된다.

public class ICUMapBalloon extends LinearLayout {

	public ICUMapBalloon(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	protected void dispatchDraw(Canvas canvas) {
		int markerHeight = 70;
        Paint panelPaint  = new Paint();
        panelPaint.setARGB(0, 0, 0, 0);
                
        RectF panelRect = new RectF();
        panelRect.set(0,0, getMeasuredWidth(), getMeasuredHeight());
        canvas.drawRoundRect(panelRect, 5, 5, panelPaint);
        
        RectF baloonRect = new RectF();
        baloonRect.set(0,0, getMeasuredWidth(), getMeasuredHeight() - markerHeight);
        panelPaint.setARGB(230, 255, 255, 255);        
        canvas.drawRoundRect(baloonRect, 10, 10, panelPaint);
        
        Path baloonTip = new Path();
        baloonTip.moveTo(7*(getMeasuredWidth()/16), getMeasuredHeight() - markerHeight);
        baloonTip.lineTo(getMeasuredWidth()/2, getMeasuredHeight() - markerHeight + 15);
        baloonTip.lineTo(9*(getMeasuredWidth()/16), getMeasuredHeight() - markerHeight);
        
        canvas.drawPath(baloonTip, panelPaint);
        
		super.dispatchDraw(canvas);
	}
}


: 위에서 반드시 구현해야할 생성자는 인자를 2개 받는 생성자로, LayoutInflater가 초기화할 때 호출되는 생성자이다. 그리고 dispatchDraw는 Layout이 그려질 때 호출되는 함수로 기본 바탕 테두리를 그리게 된다. 풍선의 모양이나 스타일을 바꾸고 싶다면 이 부분을 수정하면 된다. 이것으로 말풍선의 구현은 끝났고, Layout을 생성해주고 뿌려주는 일만 남았다.


* BalloonLayout의 생성

: 위의 클래스를 구현하고 이제 이전에 만들었던 MapActivity에서 해당하는 클래스에 layout을 적용시키고 초기화시켜줘야한다. 간단하게 onCreate 함수 안에 넣어서 초기화를 해보자. 이전의 mapOverlays를 추가했던 소스 아래에 아래의 소스를 추가하자.

        LayoutInflater              layoutInflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        ICUMapBalloon noteBalloon = (ICUMapBalloon) layoutInflater.inflate(R.layout.map_icuballoon, null);
        RelativeLayout.LayoutParams layoutParams   = new RelativeLayout.LayoutParams(200,100);
        layoutParams.addRule(RelativeLayout.CENTER_VERTICAL);
        layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
        noteBalloon.setLayoutParams(layoutParams);

: 위의 소스에서 RelativeLayout.LayoutParams로 말풍선의 기본 모양을 설정하고 그것으로 말풍선의 바탕 RelativeLayout을 설정하게 된다. 이것은 만약 ICUMapBalloon을 멤버 변수로 가지고 있으면 한번만 초기화를 해도 되는 것이므로 onCreate 안에서 초기화를 시켜주면 될 것이다. 다음은 말풍선을 띄우는 소스 코드를 구현해보자. 테스트용이므로 일단 위의 소스 바로 아래에 한번 추가해보자.

        MapController mapController = mapView.getController();
        
        mapView.removeView(noteBalloon);
        noteBalloon.setVisibility(View.VISIBLE);
        mapController.animateTo(overlayitem.getPoint());
        mapView.addView(noteBalloon, new MapView.LayoutParams(200,200,overlayitem.getPoint(),MapView.LayoutParams.BOTTOM_CENTER));
        mapView.setEnabled(false);


: 위의 소스에서 MapController 클래스를 이용해서 해당하는 위치로 이동하고, mapView에 subview로서 noteBalloon 클래스를 추가하고, mapView를 비활성화 시킴으로써 말풍선 클래스에서만 동작하도록 설정하는 것이다. 구현 결과는 아래와 같다.




: 잘된다! 모양이 투박하기는 하지만 이러한 모양을 바꾸려면 말풍선의 모양은 ICUMapBalloon에서 바탕을 그리는 모양과 직접 map_icuballoon.xml 의 모양을 수정함으로써 개선 시킬 수 있을 것이다.



* 말풍선 닫기

: 위의 말풍선을 닫을 때에는 visible을 없애주거나 직접 view를 닫아주면 된다. 말풍선을 열 때마다 위의 addView를 계속 쓸 경우에는 removeView를 하고, 위처럼 addView는 한번하고 visibility만 조정하고 싶다면 visibility를 조정하면 될 것이다. 각 경우에 대한 간단한 예는 아래와 같다.


: addView이후 removeView를 하는 경우

mapView.removeView(noteBalloon);                    
mapView.setEnabled(true);


: setVisibility로만 다루고 싶은 경우

noteBalloon.setVisibility(View.GONE);                    
mapView.setEnabled(true);

: 위의 말풍선의 x 버튼에 클릭 이벤트를 설정해서 위의 소스를 호출하거나 맵뷰에 클릭이 생겼을 경우 클릭했을 때에도 위의 소스를 호출함으로써 말풍선을 닫고 없애는 것이 가능하다. 



* 설정 변경

: 현재 위의 소스에서는 맨 아래에서 mapView를 잠그는 소스가 들어있는데, 만약 맵을 잠그는 것을 원하지 않는다면 mapView.setEnabled를 설정하지 않으면 된다.


: 말풍선의 디자인을 바꾸려면 layout.xml 을 바꾸든지 위에서 layout을 inflat 시키는 ICUMapBalloon 클래스를 바꾸면 된다. 현재는 안드로이드 마커의 위에 말풍선을 표시하기 위해 위쪽으로 살짝 옮겨놨는데, 이것은 layout 클래스에서 dispatchDraw 함수의 내용을 바꿈으로써 약간 아래로 붙일수도 있을 것이다.


끝.


- 다음 글

2013/03/03 - [Android(안드로이드) 앱 개발 기초] Fragment 기초

2014/09/24 - [Android(안드로이드) 앱 개발 기초] ContentProvider 앱 간 데이터 공유 기본

2014/10/20 - [Android(안드로이드) 앱 개발 기초] MediaPlayer 음악 재생하기

2014/10/22 - [Android(안드로이드) 앱 개발 기초] SharedPreference 자동 로그인 구현 등을 위한 기능



공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/03   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함