image

 

이것은 안드로이드 Tab UI 를 구성하는 구성요소 입니다.

안드로이드 Tab UI 는 이와같이 세 개의 다른 클래스들의 집합으로 이루어져 있습니다.

 

TabHost 는 TabUI 를 구성하는 전체 틀 입니다.

여기에는 특정한 android:id 를 가지는 TabWidget 와 TabSpec 이 포함되어야 합니다.

 

TabWidget 는  TabUI 에서 선택하는 버튼이 나오는 부분을 말하며 이것의 android:id 는 반드시 “@android:id/tabs” 가 되어야 합니다.

 

TabSpec 는 하나의 탭을 구성하는 구성요소들의 집합으로서 View 의 하위구성요소가 아니기 때문에 layout xml 파일에 직접 추가될 수 없습니다. 그래서 java 소스코드상으로 추가해 주어야 하며 layout xml 에는 이를 표시하기 위하여 “@android:id/tabcontent” 라는 android:id 를 가지는 Layout View 가 추가되어 있어야 합니다.

 

 

이렇게 글로만 보면 상당히 어렵게 보이는데 이것을 쉽게 쓰도록 만들어 놓은것이 바로 TabActivity 클래스 입니다.

아래는 TabActivity 를 이용하여 layout xml 파일 없이 TabUI 를 구성하는 예 입니다.

package net.cranix.android.cranixcontact;

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

public class CranixContact extends TabActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

final TabHost tabHost = getTabHost();
tabHost.addTab(
tabHost.newTabSpec("tab1")
.setIndicator("Contacts")
.setContent(new Intent(this,ContactsTabActivity.class))
);
tabHost.addTab(
tabHost.newTabSpec("tab2")
.setIndicator("Calllog")
.setContent(new Intent(this,CalllogTabActivity.class))
);
}
}

위의 소스에는 layout xml 파일이 사용되는 부분이 없지만 TabActivity 내부적으로 기본적인 layout 을 사용하고 있습니다.

그렇다면 TabActivity 에서 사용하는 기본적인 layout 은 무엇일까요?

 

안드로이드 소스를 직접 다운받아서 xml 파일을 뒤져보면 아래와 같은 레이아웃 파일을 발견할 수 있습니다.

<TabHost xmlns:android="http://schemas.android.com/apk/res/android" 
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TabWidget android:id="@android:id/tabs"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0" />
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"/>
</LinearLayout>
</TabHost>

이것이 바로 TabActivity 클래스가 기본으로 사용하는 layout xml 파일입니다.

위에서 말로 설명한 부분에 나와있는 대로 구성되어있는것을 확인할 수 있습니다.

 

TabActivity 를 상속받은 Activity 라면 기본적으로 위와같은 layout xml 파일이 contentView 로 자동으로 셋팅됩니다.

이것을 염두해 두고 개발을 해야지 오류를 피할수 있습니다.

 

그럼 내가만든 layout xml 을 TabActivity 에 띄우는 예제를 만들어 보겠습니다.

먼저 layout 을 구성합니다 파일이름은 main.xml 입니다.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:text="@+id/TextView01"
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button android:text="@+id/Button01"
android:id="@+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>

 

이것을 TabActivity 에 띄우는 java 코드는 아래와 같습니다.

package net.cranix.android.testtabactivity;

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

public class TestTabActivity extends TabActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
final TabHost tabHost = getTabHost();

getLayoutInflater().inflate(R.layout.main, tabHost.getTabContentView());

tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator("tab1").setContent(R.id.TextView01));
tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator("tab2").setContent(R.id.Button01));
}
}
 
 
TabSpec.setContent 에 view 를 지정하려면 반드시 @”android:id/tabcontent” 의 하위 뷰 여야 합니다.
그래서 자신이 만든 layout 을 기존에 있던 tabHost 의 tabContentView 에 inflate 를 활용하여 붙혀주는 것 입니다.

 

위의 굵은 글씨에 의해 inflat 가 실행된 이후에는 layout 을 아래와 같이 인식합니다.

<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TabWidget android:id="@android:id/tabs"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_weight="0" />
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1">
<TextView android:text="@+id/TextView01"
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button android:text="@+id/Button01"
android:id="@+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
</LinearLayout>
</TabHost>

결국 위와 같이 tabSpec 을 만들때 setContent 에다가 자신이 만든 layout 을 사용할 수 있게 되는것 입니다.

 

이렇게 TabActivity 가 돌아가는 구조를 알아내면 응용도 가능합니다.

아래 예제는 안드로이드 TabUI 에서 TabWidget 이 아래에 있도록 구성한 Activity 입니다.

먼저 layout 파일은 아래와같이 구성합니다.

<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1">
<TextView android:text="@+id/TextView01"
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button android:text="@+id/Button01"
android:id="@+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
<TabWidget android:id="@android:id/tabs"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_weight="0" />
</LinearLayout>
</TabHost>

 

그다음 Activity 파일은 아래와 같이 구성합니다.

package net.cranix.android.testtabactivity;

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

public class TestTabActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TabHost tabHost = (TabHost) findViewById(R.id.tabhost);
tabHost.setup();

tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator("tab1").setContent(R.id.TextView01));
tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator("tab2").setContent(R.id.Button01));
}
}

실행해 보면 아래와 같이 탭이 아래에 있는것을 볼 수 있습니다.

 

image

 

여기서 중요한 것은 TabActivity 가 아니라 그냥 Activity 를 이용하였다는 것과 레이아웃 파일을 안드로이드 TabUI 에 맞게 직접 구성했다는점 입니다.

이렇게 TabActivity 를 통하지 않고 Tab 을 구현할 경우에는 반드시 tabHost.setup() 을 호출해 주어야 합니다.

여기서 TabHost view 하위에 있는 기본 뷰를 탐색해서 셋팅해 주게 됩니다.

즉 이 함수를 거치면 tabHost.getTabWidget() 과 tabHost.getTabContentView() 같은 메소드를 사용할때 null 이 반환되지 않게 됩니다.

 

결국 안드로이드 TabUI 는 기본적인 안드로이드 UI 구조를 가지고 TabUI 를 구성하기 편하게 상속하여 재작성 한 것입니다.

by cranix 2011.01.05 15:49