2010년 8월 31일 화요일

TabWidget 사용하기 -1

 

 

TabWidget은 Tab을 이용해서 서로 다른 view를 이동 할 수 있게 해주는 위젯입니다.

먼저 TabWidget의 모습을 보도록 하겠습니다.

[ TabWidget을 실행한 모습 ]

그럼, 안드로드이 개발자 사이트의 내용을 토대로 알아 보겠습니다.

1. 다음과 같이 프로젝트를 생성합니다.


2. 이클립스의 왼쪽 프로젝트 탐색기에서 res -> layout -> main.xml 을 열어서 다음과 같이 편집합니다.

<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/tabhost"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent">
            <TextView 
                android:id="@+id/textview1"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent" 
                android:text="this is a tab" />
            <TextView 
                android:id="@+id/textview2"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent" 
                android:text="this is another tab" />
            <TextView 
                android:id="@+id/textview3"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent" 
                android:text="this is a third tab" />
        </FrameLayout>
    </LinearLayout>
</TabHost>

TabHost 안에 TabWidget이 위치함을 눈여겨 보기 바랍니다.


3. 프로젝트탐색기에서 src -> my.HelloTabWidget -> HelloTabWidget.java 를 열어서 다음과 같이 편집합니다.

package my.HelloTabWidget;

import android.app.TabActivity;
import android.os.Bundle;
import android.widget.TabHost;

public class HelloTabWidget extends TabActivity  {
 TabHost mTabHost = null;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    
        mTabHost = getTabHost();
        
        mTabHost.addTab(mTabHost.newTabSpec("tab_test1").setIndicator("TAB 1").setContent(R.id.textview1));
        mTabHost.addTab(mTabHost.newTabSpec("tab_test2").setIndicator("TAB 2").setContent(R.id.textview2));
        mTabHost.addTab(mTabHost.newTabSpec("tab_test3").setIndicator("TAB 3").setContent(R.id.textview3));
        
        mTabHost.setCurrentTab(0);
    }
}

위의 코드 중 굵은 글씨 부분만 설명하면,

TabHost - Tab으로 구성된 view를 담기위한 컨테이너(Container)
addTab() - Tab을 추가
newTabSpec() - Tab의 Spec( indicator,content,tag )을 만듬. 괄호안의 매개변수값인 tab_test1 등이 tag
setCurrentTab() - 현재 탭을 결정. 처음엔 일반적으로 첫번째 탭(인덱스 0)이 지정됨

와 같습니다.


4. Ctrl + F11 로 실행합니다.

[ 두번째 탭이 선택된 모습 ] 

 

이번에는 TabWidget을 출력할 때 상단의 TitleBar( HellowTablWidget 글씨가 보이는 부분 )을 없애도록 해보겠습니다.

이 강좌는 TabWidget 사용하기 1 에서 이어집니다.

1. 이클립스 프로젝트탐색기에서 res -> AndroidManifest.xml 을 열어서 다음과 같이 편집합니다.

아래 그림의 빨간색박스 부분을 눌러서 AndroidManifest.xml 파일 편집합니다.


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="my.HelloTabWidget"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:theme="@android:style/Theme.NoTitleBar">
        <activity android:name=".HelloTabWidget"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
    <uses-sdk android:minSdkVersion="6" />

</manifest>

원래 코드에서 바뀐 부분은 다음 application 태그 입니다.
<application android:icon="@drawable/icon" android:theme="@android:style/Theme.NoTitleBar">


2. Ctrl + F11 로 실행합니다.

[ 실행결과 ]


3. 다음에는 탭에 아이콘을 넣어 보겠습니다. 다음 아이콘 이미지를 다운로드해서 바탕화면에 저장한 다음 프로젝트탐새기에서 res -> drawable-hdpi 폴더에 끌어다 넣습니다.






4. 프로젝트 탐색기에서 src -> my.HelloTabWidget -> HelloTabWidget.java 를 열어서 다음과 같이 편집합니다.

package my.HelloTabWidget;

import android.app.TabActivity;
import android.os.Bundle;
import android.widget.TabHost;

public class HelloTabWidget extends TabActivity  {
 TabHost mTabHost = null;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    
        mTabHost = getTabHost();
        
        mTabHost.addTab(mTabHost.newTabSpec("tab_test1").setIndicator("TAB 1", getResources().getDrawable(R.drawable.icon1)).setContent(R.id.textview1));
        mTabHost.addTab(mTabHost.newTabSpec("tab_test2").setIndicator("TAB 2", getResources().getDrawable(R.drawable.icon2)).setContent(R.id.textview2));
        mTabHost.addTab(mTabHost.newTabSpec("tab_test3").setIndicator("TAB 3", getResources().getDrawable(R.drawable.icon3)).setContent(R.id.textview3));
        
        mTabHost.setCurrentTab(0);
    }
}

굵은 글씨 부분에서 setIndicator메서드 부분이 변경되었습니다.


5. Ctrl + F11 로 실행합니다.

[ 실행결과 ]

[출처] Android Side - http://www.androidside.com/bbs/board.php?bo_table=B46&wr_id=1166

2010년 8월 29일 일요일

알바할때

 

이번주에 첫출근으로 주말알바를 시작했다

경대에 꾼노리라고... 아무것도 모른체 새로 해보는 일이라며

재밌게 하려고 갔던곳.. 하지만 내뜻되로 되지않는 상황들..

분명 내가 잘못 하고 있는건지.. 일은 열심히 함에도(내가 이런말 하는건 건방질라나..무튼)

누군가의 인정을 바라고 칭찬을 듣고 싶고 잘한다잘한다 해주면 더 열심히 할텐데 누구하나

나한테 인정을 베풀어 주지않아 ㅜㅜㅜㅜㅜ

같이 알바하는 여자얘 한명이 첫날에 많이 신경써주고 처음이라 힘들죠 라며 말한마디

건네줌에 생각이 깊은 아이라는 인상이 찍혓다

역시 사람은 첫인상이 중요한가 보다.. 나는 꾼노리에서 어떻게 인상이 각인 되어있을까..

다시한번 짚어본다..

 

이번주 첫 알바를 마친 소감으로는

누구 말처럼 돈이 걸린건 재밌게 할 수 없다는게 맞는말인가 싶다..

그 누가 이렇게 말했을때 속으로 난 재밌게 할 수 있다고 다짐햇건만

하루아침에 이렇게 무너져 버리는 내 마음은 어떻게 할수가 없네..

 

육체적인 힘듬보다 정신적인 힘듬에 좀더 약한 나는 이런게 더 힘들다..

하지만 난 내할일에 열심히 하고 손님접대에 신경써서 즐겁게 해야겟다

화                            이                             팅                     ! 얍 !

2010년 8월 26일 목요일

당당하게 걷는법

 

 

걷는걸 잘해야 건강할 수 있다

걷는거 조차 못한다면 몸을 버리고 몸을 버리게 되면

자연히 마음도 버리게 된다.

 

고로, 걷는걸 잘 걸어야 몸과 마음이 건강할 수 있단 말

건강하게 걷는 방법은

가슴을 펴고 어깨를 내리며 무엇보다 중요한

무게중심을 뒷꿈치에 두고 걷는다는 걸 명심하길 바란다.

 

원래 인간은 불공평 하기에 부족한 환경에 주눅 들기 보다는

내가 최고라는 겸손한 당당함을 안고 앞으로 나아가야 할것이다.

2010년 8월 4일 수요일

안드로이드 레이아웃

Hierarchy of Screen Elements

 

개요 : 안드로이드 의 기본 클래스는 Activity(android.app.Activity) 클래스임.

Activity 클래스는 아주 많은 것을 할 수 있지만 지 혼자서는 화면에 아무짓도 못한다.

Activity 클래스에 화면기능을 하기 위해서는 View, Viewgroups 와 항상 같이 작업을

해줘야 한다.

 

1.  Views

View(android.view.View) 클래스는 화면의 사각형 영역에 있는 컨텐츠나 화면 레이아웃 을

담당한다.

즉 화면영역에 오브젝트들을 배치하고,위치를 재고,그리고,포커싱을 바꾸고,스크롤을 하는등의

일을 한다.

또한 View 클래스는 위젯(화면에 어떤 것을 그리는 모든 행위를 하는 클래스들의 집합)

기본 클래스이며, 이 위젯에 해당하는 클래스들로는 Text, EditText, InputMethod

, MovementMethod, Button, RadioButton, Checkbox, and ScrollView. 등이 있다.

 

2.  Viewgroups

Viewgroup(android.view.Viewgroup) 은 화면의 Layout 이다. 즉 각각의 View 들을 합쳐서

전체 구조를 그리고 화면의 전체 Layout 을 그려낸다.

 

3.  A Tree-Structured UI

Activity User Interface View Viewgroup 을 이용한 Tree 형태로 구성할 수 있다.


                                                                               [그림 – 1] A Tree

그림에서 보듯이 Viewgroup 이 다수의 View 를 포함하고 있고 Viewgrpup 도 포함하고

있는 것을 볼 수 있다.

예를 들면 RadioButton 컴포넌트를 여러개 둔 하나의 Viewgroup 을 만들수 있는 것이다.

이렇게 구성된 Tree 구조물을 화면에 표현하기 위해서 Activity 클래스의 setContentView()

메쏘드를 호출한다.

여기서, Activity 가 시스템으로부터 화면을 그려라, 또는 포커싱을 하라는 등의 노티를 받게 되면

트리의 최상위 root node 로 드로잉(Draw()) 요청을 하게된다. Root node 는 요청을 받게

되면 하위 child node 까지 모두 드로잉 하라는 명령을 전달하게 된다.

 

4.  LayoutParams: How a Child Specifies Its Position and Size

모든 Viewgroup ViewGroup.LayoutParams 를 상속받은 nested class 를 사용한다.

이 서브클래스 는 하위 클래스의 크기,위치,프로퍼티 등을 정의한다.

 


                                                 [그림-2] LayoutParams

모든 Viewgroup width height 를 가지고 있으며 다수의 Viewgroup border, margin

값을 가지고도 있다.

 

 

Common Layout Objects

 

다음으로는 어플리케이션에서 사용할수 있는 대부분의 Viewgroup 에 대해서 알아본다.

 

1.  FrameLayout

FrameLayout 은 가장 단순한 layout 중에 하나이다. 이 레이아웃은 빈 레이아웃 으로서

나중에 객체 하나를 넣을수 있게 되어있다. 얘를 들면 사진을 보여주는 틀에서 사진만

계속 교체되는 형태로 이 틀이 FrameLayout 이다.

 

 

 

 

 

2.  LinearLayout

LinearLayout 은 이름에서 볼수 있듯이 모든 children 을 한줄로 정렬하는 기능이다.

Children(child noed 의 콤포넌트) 사이의 마진, 그리고 gravity(좌우중 정렬,) 도 제공한다.

그리고 LinearLayout 에는 weight 라는 개념이 있는데, weight 는 각 컴포넌트 들이

빈공간을 얼마나 미리 확장 시켜놓을수 있느냐 에 대한 설정 값이다.

쉽게 얘기하면 Html 에서 textbox 를 하나 만들고 태그로 size 를 줘서 미리 입력

사이즈를 확보하는 것과 같은 개념이다.

 

아래 그림을 예로 들면

/우 그림모두 gravity left 이며, 좌측 은 weight 가 모두 디폴트값(0) 로 세팅

되어있다. Textbox Width FILL_PARENT(풀화면) 로 세팅되어 있고, 나머지 콤포넌트는

WRAP_CONTENT 로 세팅되어 있다.

반면 우측그림의 Comments textbox weight 1 로 세팅되어 있다.

Name textbox 1로 세팅했으면 Name Comments textbox height

같아졌을 것이다.

 

                                                                  [그림-3] LinearLayout(Vertically)

Horizontal LinearLayout 은 첫번째 컴포넌트의 첫번째 텍스트 라인을 기준으로 나머지

콤포넌트를 정렬시키는 기능을 가지고 있다.(이러한 기능은 왠만한 4GL 툴에서는 메뉴로 제공하지만..)

이기능을 사용하지 않으려면 layout XML 에서 android:baselineAligned="false" 처럼

세팅하면 된다.

 

 

3.  TableLayout

TableLayout 은 말그대로 row column 을 가지고 있는 테이블을 만든다.

그렇지만 Html 처럼 Border 는 표시되지 않는다. 아래그림에서 도트 표시되어 있는

라인이 실제로는 보여지지 않는다는 이해를 돕기 위해 임의로 표시해놓은 것이다.

(테이블이 View 로 들어가지 않고 Layout 으로 들어간 것이 특이하다)

 

                                                                      [그림-4] TableLayout

 

4.  AbsoluteLayout

이번 레이아웃은 콤포넌트들을 X/Y 위치에 포커싱 하기 위한 레이아웃이다.

Where(0,0) 하면 좌측 상단 꼭지점을 말한다.(일반적으로 JAVA Layout 과 같다고 생각하면 된다.)

주의할점은 Margin 이 지원되지 않으며, 권장할 만한 사항은 아니지만 콤포넌트 끼리 겹쳐서

포지셔닝 되는 것이 가능하다.

또한 AbsoluteLayout 은 정말로 잘 사용할 자신이 없으면 사용하지 않는 것이 좋다.

왜냐하면 디바이스 별로 다르게 동작할 수 있기 때문이다.(그래서 페이지에 딸랑 3줄로

설명이 되어 있었군요..) 

 

5.  RelativeLayout

RelativeLayout 은 각 콤포넌트들 끼리 서로 위치에 대한 정보를 주고 받는 Layout 을 말한다.

기준이 되는 콤포넌트가 우선 하나 정해져야 하며, 나머지 콤포넌트 들은 기준 콤포넌트를

우선으로 해서 자신의 위치를 세팅할수 있다.

 

아래 그림을 보면. 기준이 되는 TextView 컴포넌트가 우선 자리를 잡고 있다.

그아래 EditText below 항목을 보면 “label1” 으로 되어 있다. 이것은 기준 콤포넌트인

TextView ID 가 되겠다. 그러니까 TextView 의 아래에 나 EditBox 가 위치하고 있다는

것을 의미한다.

RelativeLayout 클래스의 Constants 를 살펴보면 POSITION_BELOW , POSITION_ABOVE

등이 있는 것을 확인할 수 있다.

 

[그림-5] RelativeLayout

 

 

 

출처 - http://mnd777.egloos.com/1047906

Android UI 개발기: XML 안쓰고 UI 코딩하기

 

이전 포스트에서 Android로 계산기를 만든다고 했습니다.

그리고 계산기를 만들기 위해 developer.android.com 의 문서들을 정독하기 시작했습니다. Amazon Kindle로 Android Wireless Application Development를 구매하여 읽어보고 있고요. 그런데 생각처럼 쉽지가 않았습니다.

코드로 UI 작성하기가 쉽지 않다.

GUI 개발시 위지윅 에디터를 거의 사용하지 않는 버릇 때문에, 대부분의 UI 개발을 코드만으로 해오고 있었습니다. 복잡한 GUI 만들 때는 코드로 하면 더 어렵지 않느냐 생각하실 수도 있지만 결코 그렇지 않습니다. 복잡도가 높으면 높을수록 코드로 GUI를 뽑아내는 것이 더 높은 생산성을 보입니다. 컴포넌트들을 적절한 범주로 묶어 collection에 넣어 일괄처리할 수도 있고, 화면은 1장이여도 논리적인 기능 단위로 클래스를 분리할 수 있어 편리하기 때문입니다. 예를 들어 계산기를 만든다고 할 때, 버튼이 여러개가 있는데 이것들을 디자이너로 배치하고, 각 아이디를 할당하고 이벤트 핸들러를 붙이는 것은 곤욕입니다. for loop으로 생성하고 화면 resolution에 따라 적절히 컴포넌트의 크기위 위치를 할당하는 것이 개발속도가 더 빠릅니다. UI 생성 코드 로직들을 다 기억한다는 전제하에 유지보수하기도 훨씬 더 편리해집니다. 아주 오랜 시간이 지나, 어떻게 만들었었는지 기억을 거의 못할 때면, 디자이너를 열어서 버튼을 더블클릭하여 어느 핸들러와 연결되어있는지 확인하는 것도 더 편하겠지만, 우리는 문서 작성능력이 있고 기억해야할 것을 어딘가 노트해둘 수 있는 능력을 가진 인간입니다. (게다가 우리에겐 Swing, SWT, JavaFX를 지원하는 MiG Layout이 있습니다. :D )

안드로이드는 UI 생성을 XML 말고도 코드로도 생성할 수 있게 해줍니다. 하지만 그 지원이 생각만큼 높지 않습니다. 문서가 부족하기 때문입니다.

계산기의 현재 숫자를 표현하는 TextView를 만들려고 합니다. 그러면

<TextView
	android:text="1,048,576"
	android:gravity="center_vertical|right"
	android:background="#000000"
        android:textSize="36"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:layout_weight="1"/>

이렇게 만들면 됩니다. UI가 XML로 분리되어 가지는 장점들은

  • 로직과 UI를 파일단위로 분리할 수 있다.
  • 소스코드 변경없이 리소스만 변경하여 UI를 바꿀 수 있다.
  • Portrait/Landscape, 화면 해상도 별, 언어별로 XML 파일을 따로 만들어두고 하나의 로직에 연결하여 사용할 수 있다.
  • 디자이너(위지윅에디터)를 사용할 수 있다.

반면에 동일한 기능을 하는 UI를 코드로 작성해보면

view = new TextView(this);
view.setText("1,048,576");
view.setGravity(Gravity.CENTER_VERTICAL|Gravity.RIGHT);
view.setBackgroundColor(0x000000:
view.setTextSize(36.0f);
view.setLayoutParams(new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0.0f));
  • 로직과 UI는 클래스 단위로 분리할 수 있다.
  • 소스코드 재컴파일, 그저 하면 된다.
  • 수십년동안 많은 프로그래머들이 XML로 분리된 UI 없이도 가변 사이즈를 지원하는 UI를 코드로 작성해왔었고, 다국어 지원을 추가함에도 아무런 문제가 없었다.

코드가 더 복잡해지는 것은 아닙니다.

그러면 왜 코드로 UI 만들기가 어렵다고 했나요?

그 이유는, Android가 XML로 UI 만들기를 권장하고 있기 때문입니다. 코드로 UI 만드는 사람을 위한 친절한 문서가 거의 없기 때문입니다.

위의 TextView 생성 코드를 보시면, 수직 중앙 정렬과 우측 정렬을 하기 위해 android.view.Gravity 의 상수를 가져다 쓰고 있습니다. API 문서에는 setGravity(int)로만 되어 있고, See also 섹션에 Gravity 클래스의 링크가 있습니다. 후다닥 찾기가 애매합니다. XML에서는 그저 android:gravity=”center_vertical|right” 라고 입력해주면 되는데 말입니다.

LinearLayout을 쓰고 싶은데, d.android.com 에서 제공하는 문서는 오직 XML 뿐입니다. 위의 코드를 보면 child 컴포넌트에 setLayoutParams(new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0.0f)) 를 실행하여 android:layout_width=”fill_parent”, android:layout_height=”wrap_content”, android:layout_weight=”0″ 과 똑같은 동작을 하도록 했습니다.

가장 큰 어려움은 TextView 클래스에 setLayoutWidth 나 setLayoutHeight, setLayoutWeight 같은 이름을 가진 메서드가 존재하지 않는다는 것입니다. 결국, XML 문서만을 보고 추측하여 쉽게 코드로 옮길 수 없다는 문제가 있습니다.

XML에서 할 수 있는 모든 기능을 API로도 할 수 있습니다. 하지만 쉽게 찾을 수 없는 것이지요.

코드로 UI를 만드는 것이 어렵다고 했는데, 왜 구지 코드로 UI를 만들려고 하나요?

동일한 속성을 가지는 컴포넌트를 여러개 만들려고 할 때, XML 에서는 copy and paste가 불가피합니다. 계산기 앱의 경우 버튼이 4×4로 16개가 있습니다. 버튼의 배경색을 검정색에서 회색으로 바꾸고자 한다면 16번 손을 움직여야 합니다. 코드로 하면 루프 몇 번 돌아서 해결할 수 있는데 말입니다.

 1   private void createButtons()
 2   {
 3     for(int i=0; i<nums.length; i++)
 4     {
 5       final int number = i;
 6       nums[i] = new Button(getContext());
 7       nums[i].setText(String.valueOf(number));
 8       nums[i].setGravity(gravity);
 9       nums[i].setTextSize(textSize);
10       nums[i].setOnClickListener(new View.OnClickListener() {       
11       @Override
12       public void onClick(View v) {
13         action.processNumber(number);
14       }
15     });
16     }
17            
18     for(final Operator op : Operator.values())
19     {      
20       Button button = new Button(getContext());
21       button.setText(op.text());
22       button.setGravity(gravity);
23       button.setTextSize(textSize);
24       button.setOnClickListener(new View.OnClickListener() {
25       @Override
26       public void onClick(View v) {
27         action.processOperator(op);
28       }        
29       });        
30       operatorButtons.put(op, button);
31     }
32   }

이렇게..  안드로이드 계산기가 만들어져가고 있습니다.

 

 

 

 

출처 - http://xrath.com/2009/11/android-ui

2010년 8월 3일 화요일

유용한 이클립스 단축키 모음

Java Editor 단축키
Ctrl + Shift + M : 특정 클래스 Import 시키기
Ctrl + Shift + O : 자동으로 Import 시키기
Ctrl + Shift + F : 코드 자동 정리
Ctrl + Shift + G : 특정 메써드나 필드를 Reference하고 있는 곳을 찾는다.
Ctrl + 1 : Quick Fix. 에러가 발생했을 경우 Quick Fix를 통해 쉽게 해결이 가능하다.
Ctrl + Shift + / : 블럭 주석 설정
Alt + Shift + UP : 커서를 기준으로 토큰단위 블럭지정
Alt + Shift + DOWN : 커서를 기준으로 토큰단위 블럭해제
CTRL + L : 특정 줄번호로 가기
CTRL + D : 한줄삭제
Alt + Shift + J : 자동으로 주석 달기 (메소드나 멤버변수에 포커스 두고 실행)

 

Window 이동
F10 : 메뉴창을 활성화
Ctrl + F8 : 다음 Perspective로 이동
Ctrl + N : 새로운 파일 및 프로젝트 생성.
Ctrl + Shift + Down : Java Editor에서 다음 member로 이동.
Ctrl + F7 : 다음 View로 이동.
Ctrl + Shift + F7 : 이전 View로 이동.
Alt + <- : 이전 작업 화면
Alt + -> : 다음 작업 화면
F12 : 컴파일 중 에러등으로 포커스가 다른데로 갔을 때 Editor 로 커서 이동
Ctrl + 1 : 컴파일 에러가 발생한 곳에서 Ctrl + 1을 누를 경우 컴파일 에러에 대한 해결책을 제시

 

디버깅 단축키
CTRL + Shift + B : 현 커서의 위치에 브레이크 포인터 설정/해제
F11 : 디버깅 시작
F8 : 디버깅 계속
F6 : 한줄씩 실행(Step Over)
F5 : 한줄씩 실행하되 함수일 경우 그 함수 내부로 들어감(Step Into)
CTRL + R : 현재 라인까지 실행(Run to Line)

 

Refactoring 단축키
Shift + ALT + 알파벳 : Refactoring을 위한 단축키 임.

 

RUN 단축키
Ctrl + F11 : 이전에 실행되었던 Run파일 실행.

2010년 8월 2일 월요일

구글맵 API 활용하기 - (4) 위성 지도로 보이기

위성 지도 보이기

MapActivity에서 MapView 객체 가져오기

MapActivity 소스코드 내에서 findViewById 메서드를 이용하여 MapView객체의 레퍼런스를 찾아오기 위하여 android:id 속성을 추가한다.

변경할 파일은 <PROJECT>/res/layout/main.xml이다.

  1. <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
        <com.google.android.maps.MapView
            android:id="@+id/testMapView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:enabled="true"
            android:clickable="true"
            android:apiKey="03d0eYuU20SMHZARFYNbqBRkKERXqVPMMieAk8g"
            />

    </LinearLayout>

 

<PROJECT>/src/com.jjis.test/R.java 파일에 id와 관련된 속성이 inline class로 생성되었음을 알 수 있다.

그렇다면 생성된 ID를 이용해서 MapView 객체의 레퍼런스를 가져 오도록 findById 메서드를 이용해 보자. 아래와 같이 맴버 변수로 MapView 를 하나 선언하고 onCreate 메서드에 fiewViewById를 호출해서 mapView 변수에 할당하자. 여기서 View를 찾기위한 ID는 R.java의 R.id.testMapView를 이용할 수 있다.

 

  1. package com.jjis.test;

    import android.os.Bundle;

    import com.google.android.maps.MapActivity;
    import com.google.android.maps.MapView;

    public class MapTest extends MapActivity {
       
        private MapView mapView;
       
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            mapView = (MapView)findViewById(R.id.testMapView);
        }

        @Override
        protected boolean isRouteDisplayed() {
            // TODO Auto-generated method stub
            return false;
        }

    }

 

MapView의 Satellite 속성 변경

이제 MapActivity에서 지도를 보여주던 MapView의 레퍼런스를 가져 왔으니 단순히 setSatellite 메서드를 이용해서 true속성만 전달해 주면 된다.

  1.     @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            mapView = (MapView)findViewById(R.id.testMapView);
  2.         mapView.setSatellite(true);
        }

 

이제 결과를 확인한다

 

 

출처 - http://zbum.springnote.com/pages/2658038

 

 

구글맵 API 활용하기 - (3) 지도에 확대/축소 기능 추가하기

강좌 작성환경
SDK Version : Android SDK 2.0, release 1
ADT Version : 0.9.4

추후 SDK업데이트로 인해 글의 내용과 최신 SDK 내용간 차이가 있을 수 있습니다.

* SDK 2.0 기준 업데이트 완료됨 : 2009/11/12

저번 강좌 이후로 공백이 좀 길었네요.
이래저래 제가 자유롭게(?) 글을 쓸 환경이 되질 않다보니 -_-... 이렇게 띄엄~띄엄 포스팅을 하게 되네요.
(물론 최근에 렌즈 구한다고 장터매복 했던 이유도 없지않게 있겠지만요, ㅎㅎ;;;)

긴 이야기는 이쯤에서 접어두고, 오늘은 저번에 예고했던 대로, 맵을 컨트롤하는 기능을 추가해보도록 하겠습니다.
맵을 컨트롤하려면, 깜찍이님 강좌에서처럼 할 수도 있지만, 저 방법은 제가 보는 책 (Professional Android Application Development)에 나와있는 방법인데다가, 제 실력이 딸려서인지는 몰라도 잘 이해가 가지 않아서, 메뉴 이용법 및 Toast 이용법까지 익힐 수 있도록 다른 방식으로 작성하는 법에 대해서 강좌를 진행하도록 하겠습니다.

일단, 메뉴를 이용해서 지도 확대/축소 버튼을 추가할 것입니다. 다음과 같이 말이죠.



사실, 메뉴 아이템(지도 확대, 축소 버튼)에 아이콘도 넣을 수 있지만, 이번 강좌에서는 사정상(...) 아이콘 넣는 것은 생략하고 지나가도록 하겠습니다.

일단, 메뉴부터 넣어보도록 하죠. 메뉴를 넣으려면 onCreateOptionsMenu()와 onOptionsItemSelected() 메소드를 오버라이드 해야 합니다. onCreateOptionsMenu()에서는 메뉴에 항목들을 추가해주고, onOptionsItemSelected()에서는 사용자가 실제로 메뉴 항목을 눌렀을 경우 처리할 작업을 입력해줍니다.

다음과 같이 onCreateOptionsMenu()메소드와 onOptionsItemSelected() 메소드를 추가합니다.
01.package com.androidhuman.HelloMaps;
02.  
03.import com.google.android.maps.MapActivity; // Activity가 아닌 MapActivity를 추가합니다.
04.  
05.import android.os.Bundle;
06.import android.view.Menu; // 메뉴를 사용하기 위해 import합니다.
07.import android.view.MenuItem; // 메뉴를 사용하기 위해 import 합니다.
08.  
09.public class HelloMaps extends MapActivity { // MapActivity를 상속합니다.
10.     /** Called when the activity is first created. */
11.    @Override
12.    public void onCreate(Bundle savedInstanceState) {
13.        super.onCreate(savedInstanceState);
14.        setContentView(R.layout.main);
15.                  
16.    }
17.          
18.  
19.@Override 
20.protected boolean isRouteDisplayed() { // MapActivity를 상속하면, 이 메소드를 추가해줘야 합니다.
21.    // TODO Auto-generated method stub
22.    return false;
23.}
24.public boolean onCreateOptionsMenu(Menu menu){
25.    super.onCreateOptionsMenu(menu);
26.    // 메뉴에 항목을 추가하려면 이 메소드에서 추가해줍니다.    
27.    return true;
28.}
29.  
30.public boolean onOptionsItemSelected(MenuItem item){
31.    super.onOptionsItemSelected(item);
32.          
33.    return true;
34.}
onCreateOptionsMenu() 메소드 오버라이드하고, 이를 수정함으로써 메뉴를 눌렀을 때 나오는 항목들을 변경할 수 있으며, onOptionsItemSelected() 메소드를 오버라이드하고 수저암으로써 메뉴의 각 항목을 눌렀을 때 나오는 항목들을 변경할 수 있습니다.

그럼, 먼저 메뉴 항목을 추가해볼까요??

아까 오버라이드한 onCreateOptionsMenu() 메소드를 다음과 같이 수정합니다.

1.public boolean onCreateOptionsMenu(Menu menu){
2.    super.onCreateOptionsMenu(menu);
3.    MenuItem zoomin = menu.add(0, 1, Menu.NONE, "지도 확대"); // 메뉴에 항목 추가
4.    MenuItem zoonout = menu.add(0, 2, Menu.NONE, "지도 축소"); // 메뉴에 항목 추가
5.      
6.    return true;
7.}

메뉴의 항목을 추가해주기 위해서는 add()메소드를 사용하면 됩니다.

public abstract MenuItem add (int groupId, int itemId, int order, CharSequence titleRes)
- groupid : 메뉴 항목의 그룹을 지정합니다.
- itemId : 각 메뉴 항목의 고유의 번호입니다.
- order : 각 항목의 정렬 방식입니다.
- titleRes : 메뉴 항목의 이름입니다.


위의 과정까지 추가하고 프로젝트를 실행한 후, 메뉴를 눌러보면 위 스크린샷과 같이 메뉴가 뜨는 것을 볼 수 있습니다. 하지만, 아직까지는 메뉴를 눌러도 아무런 동작을 하지 않을 것입니다. 메뉴 항목을 누름에 따라 어떻게 반응할지 지정해 주지 않았기 때문이죠.

그럼, 이제부터 메뉴 항목에 따라 어떤 동작을 할 지 지정해 주도록 하겠습니다.

그 전에, 우리가 하고싶은 일이 지도의 확대/축소, 즉 MapView를 컨트롤하는 일이므로 MapView의 컨트롤러를 받아와야 합니다. MapView의 컨트롤러는 MapView 객체를 받아온 후, getController() 메소드를 통해 받아올 수 있습니다.

우리는 여기에서 지도의 확대/축소를 구현하고, 확대/축소 레벨이 최대에 도달했을 경우 사용자에게 이를 알려주는 기능까지 구현해보도록 합시다. 지도를 확대/ 축소하는 등 지도를 '컨트롤' 하려면 MapView의 컨트롤러를 받아야 하는데, 이를 위해 MapView에 id를 지정해주어야 합니다. 그래야 findViewById()를 통해 MapView 객체를 받아올 수 있게 되겠죠. 다음과 같이 MapView의 ID를 지정해주도록 합니다.

1.<com.google.android.maps.MapView
2.    android:id="@+id/mapview"
3.    android:layout_width="fill_parent"
4.    android:layout_height="fill_parent"
5.        android:focusable="true" 
6.    android:clickable="true"
7.        android:apiKey="내 API KEY" />


MapView 객체과 그의 컨트롤러인 MapController를 사용하기 위해, 필요한 요소들을 import 하고 다음과 같이 코드를 수정합니다.

01.package com.androidhuman.HelloMaps;
02.  
03.import com.google.android.maps.MapActivity; // Activity가 아닌 MapActivity를 추가합니다.
04.import com.google.android.maps.MapController;
05.import com.google.android.maps.MapView;
06.  
07.import android.content.Context;
08.import android.os.Bundle;
09.import android.view.Menu;
10.import android.view.MenuItem;
11.import android.widget.Toast;
12.  
13.public class HelloMaps extends MapActivity { // MapActivity를 상속합니다.
14.    MapView v; // MapView를 연결해줄 객체를 생성합니다.
15.    /** Called when the activity is first created. */
16.    @Override
17.    public void onCreate(Bundle savedInstanceState) {
18.        super.onCreate(savedInstanceState);
19.        setContentView(R.layout.main);
20.        v = (MapView)findViewById(R.id.mapview);
21.          
22.    }
23.          
24.  
25.@Override 
26.protected boolean isRouteDisplayed() { // MapActivity를 상속하면, 이 메소드를 추가해줘야 합니다.
27.    // TODO Auto-generated method stub
28.    return false;
29.}
30.public boolean onCreateOptionsMenu(Menu menu){
31.    super.onCreateOptionsMenu(menu);
32.    MenuItem zoomin = menu.add(0, 1, Menu.NONE, "지도 확대");
33.    MenuItem zoomout = menu.add(0, 2, Menu.NONE, "지도 축소");
34.      
35.    return true;
36.}
37.  
38.public boolean onOptionsItemSelected(MenuItem item){
39.    super.onOptionsItemSelected(item);
40.    MapController control = v.getController(); // 맵 컨트롤러를 받아옵니다.
41.    Context context = getApplicationContext(); // Toast를 띄우기 위해 Context를 받아옵니다.
42.      
43.    switch(item.getItemId()){
44.    case 1: // 지도 확대
45.        if(!control.zoomIn()){
46.            Toast toast = Toast.makeText(context, "최대 줌 레벨에 도달했습니다.", Toast.LENGTH_SHORT);
47.            toast.show(); // Toast를 표시
48.            break;
49.        }
50.        break;
51.    case 2: // 지도 축소
52.        if(!control.zoomOut()){
53.            Toast toast = Toast.makeText(context, "최소 줌 레벨에 도달했습니다.", Toast.LENGTH_SHORT);
54.            toast.show(); // Toast를 표시
55.            break;
56.        }
57.          
58.          
59.    }
60.    return true;
61.}
62.  
63.}


메뉴 항목을 선택했을 때, 이를 처리해주는 onOptionsItemSelected()메소드를 보시면, switch구문에 getId()메소드로 각 메뉴 항목의 id를 가지고 처리하는 것을 볼 수 있습니다. 때문에, 메뉴 항목을 추가할 때 이 id가 겹치지 안도록 하는 것이 중요합니다.

지도의 확대/축소는 각각 MapController 객체의 zoomIn(), zoomOut() 메소드를 사용합니다. 이 메소드들은 지도를 확대/축소하는 기능 뿐만 아니라 만약 더이상 확대/축소가 가능하지 않다면 false를 반환합니다. 따라서, 이러한 특성을 이용하여 확대/축소가 최대 레벨에 도달하였을 대 사용자에게 이를 알려주도록 작성하였습니다.



코드를 보면, 사용자에게 최대 / 최소 줌 레벨 여부를 알려주는 수단으로 Toast를 이용하였습니다.
Toast는 간단한 메시지 등을 사용자에게 전달할 때 많이 사용하는데요, 마치 그 특성이 토스터기에서 나오는 빵처럼 '톡' 튀어나오는것과 비슷합니다. ^^;;;

Toast에 관한 내용은 다음 강좌에서 다루도록 하겠습니다. :)


출처 - http://androidhuman.tistory.com/