안드로이드 플렛폼에서 Tab은 다음과 같은 3가지 요소로 이루어 진다.
- TabHost: TabWidget(Tab 버튼 모음)과 FrameLayout을 포함하는 전체 컨테이너
- TabWidget: Tab 버튼 모음을 나타내며 각각의 Tab 버튼은 text + icon (옵션)으로 이루어 진다.
- FrameLayout: 선택된 Tab에 따른 실제 내용(Tab content)를 위한 컨테이너. 모든 Tab content는 FrameLayout의 child임.
위에 설명한 3개의 component를 사용해 정상적으로 작동하는 Tab을 구성하기 위해서는 다음과 같은 몇 가지 숙지해야 할 사항들이 있다.
- TabWidget의 id와 최소높이: TabWidget의 id는 항상 "@android:id/tabs"로 설정 하여야 한다. 또 TabWidget의 최소 높이는 약 62px이다. 다시 말하면 Tab 버튼은 text + icon(옵션)으로 구성되는데 text로만 구성된 Tab 버튼도 무조건 62px정도의 높이를 차지한다. 물론 사용하는 icon에 따라 더 커질 수는 있다. (너무 작은 tab은 조작이 힘들어서가 아닐까 싶다)
- FrameLayout의 Padding: TabHost는 FrameLayout에서 상속되며 FrameLayout에서 child view들은 어떤 layout을 사용하던 FrameLayout의 좌측 상단에 배치된다(여러 child view가 있다면 제일 마지막에 배치된 child view가 나머지 view를 가려버림). 그래서 FrameLayout이 TabHost내부에 배치될 때 TabWidget을 고려하지 않고 무조건 TabHost의 최 상단에 배치 되어 TabWidget을 가려버린다. 그럼으로 사용된 TabWidget의 높이만큼 FrameLayout위쪽에 padding을 주어야 한다. (TabWidget의 최소 높이가 62px임으로 최소 padding도 62px)
- TabActivity 사용: TabActivity상속 받아 Activity를 구현 할 때(Tab 자체가 Activity의 main 화면일 때) TabHost의 id는 항상 "@android:id/tabhost"로 설정 하여야 한다.
추가로, Java 코드에서 XML에 선언된 여러 컴포넌트를 연결해서 정상적으로 작동하는 Tab view를 만들려면
TabHost객체의 내부객체인 TabHost.TabSpec이라는 Tab building helper 객체를 이용하여야 한다.
TabHost에 새로운 Tab을 추가하는 것은 다음과 같이 5단계로 나뉜다.
- TabHost setup 시작: findViewById 메소드를 통해 TabHost인스턴스를 얻은 후 TabHost인스턴스에 Tab을 추가하기 위해서는 반드시 TabHost인스턴스.setup() 메소드 먼저 실행 해야함. (단, TabActivity를 사용해 구현된 Tab은 setup 필요 없음)
- helper 생성: TabHost인스턴스.newTabSpec(String형 tag이름)를 사용해 helper 객체를 생성 (추후 생성시 지정한 'tag 이름'으로 다시 소환 할 수 있음.)
- Tab button의 text 지정: helper인스턴스.setIndicator(String / String+Icon / View)를 사용해 Tab Button의 형태를 지정.
- Tab content 지정: helper인스턴스.setContent(View ID / TabContentFactory / Intent)를 사용해 Tab content를 지정. (TabContentFactory와 Intent는 추후 설명)
- TabHost에 Tab객체 등록: TabHost인스턴스.addTab(helper인스턴스)로 위에서 설정 완료(tag, indicator, content)된 Tab Building helper를 TabHost에 등록.
Static한 Tab 구현
그럼 지금까지 정리한 것을 바탕으로 static(compile-time시 형태가 결정되는) 한 Tab의 구현 예제를 보자.
Static Tab 예제 (main.xml)
접기
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
03 | android:orientation = "vertical" |
04 | android:layout_width = "fill_parent" |
05 | android:layout_height = "fill_parent" > |
07 | android:id = "@+id/tabHost" |
08 | android:layout_width = "fill_parent" |
09 | android:layout_height = "fill_parent" > |
11 | android:id = "@android:id/tabs" |
12 | android:layout_width = "fill_parent" |
13 | android:layout_height = "wrap_content" /> |
15 | android:id = "@android:id/tabcontent" |
16 | android:layout_width = "fill_parent" |
17 | android:layout_height = "fill_parent" |
18 | android:paddingTop = "69px" > |
20 | android:id = "@+id/layout" |
21 | android:orientation = "vertical" |
22 | android:layout_width = "fill_parent" |
23 | android:layout_height = "fill_parent" > |
25 | android:id = "@+id/analogClock" |
26 | android:layout_width = "wrap_content" |
27 | android:layout_height = "wrap_content" |
28 | android:layout_gravity = "center_horizontal" /> |
30 | android:id = "@+id/digitalClock" |
31 | android:layout_width = "wrap_content" |
32 | android:layout_height = "wrap_content" |
33 | android:layout_gravity = "center_horizontal" /> |
36 | android:id = "@+id/theButton" |
37 | android:layout_width = "fill_parent" |
38 | android:layout_height = "fill_parent" |
39 | android:text = "The Button.\nClick me!" /> |
접기
Static Tab 예제 (MyTab.java)
접기
01 | package com.holim.test; |
03 | import android.app.Activity; |
04 | import android.os.Bundle; |
05 | import android.widget.TabHost; |
07 | public class MyTab extends Activity { |
08 | /** Called when the activity is first created. */ |
10 | public void onCreate(Bundle savedInstanceState) { |
11 | super .onCreate(savedInstanceState); |
12 | setContentView(R.layout.main); |
14 | TabHost tabHost = (TabHost)findViewById(R.id.tabHost); |
23 | spec = tabHost.newTabSpec( "Tab 00" ); |
24 | spec.setIndicator( "Clock" ); |
25 | spec.setContent(R.id.layout); |
29 | spec = tabHost.newTabSpec( "Tab 01" ); |
30 | spec.setIndicator( "Button" ); |
31 | spec.setContent(R.id.theButton); |
35 | tabHost.setCurrentTab( 0 ); |
접기
다음은 실행 화면이다.
위에서 본 예제는 Complie-Time에 Tab view의 형태가 결정된다.
하지만 경우에 따라서 run-time에 tab이 추가로 생성되어야 할 경우도 있다.
이런 경우에는 TabHost.TabContentFactory라는 TabHost의 내부객체를 사용한다.
TabContentFactory 객체는 View createTabContent(String tag)라는 abstract callback method를 포함하며,
TabContentFactory 객체 생성 시 자동으로 호출되어 결과로 Tab content를 구성하는 View를 return한다.
Dynamic 한 Tab 구현
다음은 dynamic(run-time시 동적으로 형태가 변하는)한 Tab의 구현 예제 이다.
Static Tab 예제 (main.xml)
접기
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
03 | android:orientation = "vertical" |
04 | android:layout_width = "fill_parent" |
05 | android:layout_height = "fill_parent" > |
07 | android:id = "@+id/tabHost" |
08 | android:layout_width = "fill_parent" |
09 | android:layout_height = "fill_parent" |
10 | android:text = "@string/hello" > |
12 | android:id = "@android:id/tabs" |
13 | android:layout_width = "fill_parent" |
14 | android:layout_height = "wrap_content" /> |
16 | android:id = "@android:id/tabcontent" |
17 | android:layout_width = "fill_parent" |
18 | android:layout_height = "fill_parent" |
19 | android:paddingTop = "62px" > |
21 | android:id = "@+id/btnAddTab" |
22 | android:layout_width = "wrap_content" |
23 | android:layout_height = "wrap_content" |
24 | android:layout_gravity = "center_vertical|center_horizontal" |
25 | android:text = "Click me to add a new Tab" |
접기
Static Tab 예제 (MyDynamicTab.java)
접기
01 | package com.holim.test; |
03 | import android.app.Activity; |
04 | import android.os.Bundle; |
05 | import android.view.View; |
06 | import android.view.View.OnClickListener; |
07 | import android.widget.AnalogClock; |
08 | import android.widget.Button; |
09 | import android.widget.TabHost; |
11 | public class MyDynamicTab extends Activity { |
12 | /** Called when the activity is first created. */ |
14 | public void onCreate(Bundle savedInstanceState) { |
15 | super .onCreate(savedInstanceState); |
16 | setContentView(R.layout.main); |
18 | final TabHost tabHost = (TabHost)findViewById(R.id.tabHost); |
23 | TabHost.TabSpec spec = tabHost.newTabSpec( "Tab 00" ); |
24 | spec.setIndicator( "First Tab" ); |
25 | spec.setContent(R.id.btnAddTab); |
28 | tabHost.setCurrentTab( 0 ); |
30 | Button btnAddTab = (Button)findViewById(R.id.btnAddTab); |
33 | btnAddTab.setOnClickListener( new OnClickListener() { |
35 | public void onClick(View view) { |
37 | TabHost.TabSpec spec = tabHost.newTabSpec( "New Tab" ); |
40 | spec.setContent( new TabHost.TabContentFactory() { |
43 | public View createTabContent(String tag) { |
44 | return ( new AnalogClock(MyDynamicTab. this )); |
49 | spec.setIndicator( "Clock" ); |
다음은 실행 화면이다. 첫 Tab의 버튼을 누르면 AnalogClock이 표시되는 Tab의 추가된다.
////////////////////////////////////////////////////////////////////////////////////////////////////////
출처: http://mainia.tistory.com/550
안드로이드(android) 탭(TabActivity) 3가지 구현하기 |
개발환경 : JDK 1.5, eclipse-galileo, Android GoogleAPI 2.1, window XP |
3가지 방법으로 탭구현 예제를 기술할것이다.
첫번째는 탭 컨트롤 화면마다 위젯 컨트롤을 추가하는 것이다. 각 탭별로
화면을 꽉 채울 TextView 가 추가 된다. 추가되는 TextView는 각각 background
색깔이 틀릴것이다. 두번째는 tab 추가시 붙여진 아이디로 어떤 탭이 클릭
되었는지 판단해서 View 를 표현 하는것이다. 세번째는 Activity 화면
전체를 tab 에 추가하는 방법이다.
tab.xml
02 | android:layout_width = "fill_parent" |
03 | android:layout_height = "fill_parent" > |
04 | < TextView android:layout_width = "fill_parent" |
05 | android:layout_height = "fill_parent" |
06 | android:id = "@+id/view1" |
07 | android:background = "@drawable/blue" |
08 | android:text = "첫번째 탭 화면" /> |
09 | < TextView android:layout_width = "fill_parent" |
10 | android:layout_height = "fill_parent" |
11 | android:id = "@+id/view2" |
12 | android:background = "@drawable/red" |
13 | android:text = "두번째 탭 화면" /> |
14 | < TextView android:layout_width = "fill_parent" |
15 | android:layout_height = "fill_parent" |
16 | android:id = "@+id/view3" |
17 | android:background = "@drawable/green" |
18 | android:text = "세번째 탭 화면" /> |
화면을 구성할 Activity 는 TabActivity 를 상속받아 만든다. 상속받아 만들게 되면
getTabHost() 함수로 TabHost 객체를 리턴받을수 있다. 리턴 받은 TabHost 로
탭에 대한 데이터를 추가하면 된다. 화면을 구성할 layout xml 은 일반 Activity
처럼 setContentView 로 셋팅할수 없다. LayoutInflater 객체로 생성한다.
LayoutInflater.from(this).inflate(R.layout.tabs1,tabHost.getTabContentView(),true);
그리고 addTab 함수를 사용해 탭을 추가할수 있다. 추가할때 탭 타이틀명은
newTabSpec 에 넣으면된다. 탭을 구분할 id 는 setIndicator 이며 컨트롤을 추가는
setContent 함수를 사용하면 된다.01 | import android.app.TabActivity; |
02 | import android.os.Bundle; |
03 | import android.view.LayoutInflater; |
04 | import android.widget.TabHost; |
06 | import com.example.android.apis.R; |
08 | public class Tabs1 extends TabActivity { |
11 | protected void onCreate(Bundle savedInstanceState) { |
12 | super .onCreate(savedInstanceState); |
13 | TabHost tabHost = getTabHost(); |
14 | LayoutInflater.from( this ).inflate(R.layout.tabs1, tabHost.getTabContentView(), true ); |
16 | tabHost.addTab(tabHost.newTabSpec( "tab1" ) |
18 | .setContent(R.id.view1)); |
19 | tabHost.addTab(tabHost.newTabSpec( "tab3" ) |
21 | .setContent(R.id.view2)); |
22 | tabHost.addTab(tabHost.newTabSpec( "tab3" ) |
24 | .setContent(R.id.view3)); |
탭에 아이콘을 추가하는 방법과 탭생성시 추가한 id 로 View 함수를 통해
구분하여 각각 구현하는 예제이다. 아이콘을 추가하는 부분은 setIndicator 함수의
두번째 파라미터로 아이콘 리소스를 넘기면 된다. 이 소스에는 layout 을 구성하는
xml 이 존재하지 않는다. TabHost.TabContentFactory 을 implements 해서
createTabContent 를 오버로딩해서 구현하면 된다. 그리고 넘길 때 View 객체를
반환한다.
01 | import android.app.TabActivity; |
02 | import android.os.Bundle; |
03 | import android.widget.TabHost; |
04 | import android.widget.TextView; |
05 | import android.view.View; |
06 | import com.example.android.apis.R; |
08 | public class Tabs2 extends TabActivity implements TabHost.TabContentFactory { |
11 | protected void onCreate(Bundle savedInstanceState) { |
12 | super .onCreate(savedInstanceState); |
14 | final TabHost tabHost = getTabHost(); |
15 | tabHost.addTab(tabHost.newTabSpec( "tab1" ) |
16 | .setIndicator( "tab1" , getResources().getDrawable(R.drawable.star_big_on)) |
18 | tabHost.addTab(tabHost.newTabSpec( "tab2" ) |
21 | tabHost.addTab(tabHost.newTabSpec( "tab3" ) |
27 | public View createTabContent(String tag) { |
28 | final TextView tv = new TextView( this ); |
29 | if (tag.equals( "tab1" )) { |
30 | tv.setText( "탭컨텐츠 Indicator tab1 명 : " + tag); |
31 | } else if (tag.equals( "tab2" )) { |
32 | tv.setText( "탭컨텐츠 Indicator tab2 명 : " + tag); |
33 | } else if (tag.equals( "tab3" )) { |
34 | tv.setText( "탭컨텐츠 Indicator tab2 명 : " + tag); |
(3) Activity 를 Tab 별 화면에 추가하기 |
3번째 방법도 layout xml 이 존재하지 않는다. setContent 함수에 호출할 Activity
클래스를 넣어주면 된다. 화면전환할때 사용하는 Intent 객체를 쓰면 된다.
그리고 3번째 탭에서 Intent.FLAG_ACTIVITY_CLEAR_TOP 를 썻는데 이것은
탭을 클릭할 때 마다 내부에 표현되는 컨텐츠가 리플레쉬 되게 하는 옵션이다.
01 | import android.app.TabActivity; |
02 | import android.os.Bundle; |
03 | import android.widget.TabHost; |
04 | import android.content.Intent; |
06 | public class Tabs3 extends TabActivity { |
09 | protected void onCreate(Bundle savedInstanceState) { |
10 | super .onCreate(savedInstanceState); |
12 | final TabHost tabHost = getTabHost(); |
14 | tabHost.addTab(tabHost.newTabSpec( "tab1" ) |
15 | .setIndicator( "list1" ) |
16 | .setContent( new Intent( this , ListSampleView1. class ))); |
18 | tabHost.addTab(tabHost.newTabSpec( "tab2" ) |
19 | .setIndicator( "list2" ) |
20 | .setContent( new Intent( this , ListSampleView2. class ))); |
23 | tabHost.addTab(tabHost.newTabSpec( "tab3" ) |
24 | .setIndicator( "destroy" ) |
25 | .setContent( new Intent( this , Controls2. class ) |
26 | .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))); |
예제에서 파라미터로 넘긴 Class 들은 Activity 클래스들이다.
이제 이런 내용들을 기초로 해서 좀더 업그레이드 해보자. 탭에 마우스를 올렸을때, 클릭했을때
이벤트를 인식해서 색깔을 바꾼다던지 그림을 바꿔서 좀더 고급스러운 탭을 만들어 보자...
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
출처: http://mainia.tistory.com/576
Android(안드로이드) 에서 탭을 구현할 때 탭별 색상변경과 아이콘 넣어 디자인 하기 |
개발환경 : JDK 1.5, eclipse-galileo, google API 7, window XP |
이전 강좌에서도 보았지만 탭을 그대로 두기에는 어딘가 모르게 미흡하다.
색깔도 변경하고 원하는 아이콘을 넣어서 좀더 고급스럽게 만들고 싶을것이다.
안드로이드에서 제공하는 기본색은 그림을 봐서 알겠지만 Grey 이며 클릭시 색깔이 바뀌었다가
놓으면 다시 원래색깔로 돌아온다.
이 색깔을 바꾸어 보는데 예제의 내용은 탭 호스트에 포함되어있는 자식 탭들을 모두 불러와
for 문을 돌면서 동일한 색깔로 바꾸는 것이다.
// TabHost 에 포함된 Tab의 색깔을 모두 바꾼다
for(int i=0;i<tabHost.getTabWidget().getChildCount();i++){
tabHost.getTabWidget().getChildAt(i)
.setBackgroundColor(Color.parseColor("#734512"));
}
일괄적으로 적용했더니 구분이 가지 않는다. 개별적으로 바꾸고 싶다면 다음과 같이 쓰면 된다.
개발 탭을 알아내는 함수는 getChileAt(i) 이다. i 값은 제일 왼쪽 탭부터 0 으로 시작한다1 | /** TabHost 에 포함된 Tab의 색깔을 모두 바꾼다, 개별적용 */ |
2 | tabHost.getTabWidget().getChildAt( 0 ) |
3 | .setBackgroundColor(Color.parseColor( "#734512" )); |
4 | tabHost.getTabWidget().getChildAt( 1 ) |
5 | .setBackgroundColor(Color.parseColor( "#4E4E9C" )); |
위의 예제에서 아이콘을 넣어 더 고급스럽게 만들어 보자.
아이콘은 drawable 폴더에 넣고 소스에서 getResources().getDrawable() 함수를 호출해
필요한 아이콘의 int 값을 넘겨준다.1 | firstTabSpec.setIndicator( "First Tab Name" , getResources().getDrawable(R.drawable.guitar)); |
2 | firstTabSpec.setContent( new Intent( this ,FirstTab. class )); |
4 | secondTabSpec.setIndicator( "Second Tab Name" , getResources().getDrawable(R.drawable.quicktime)); |
5 | secondTabSpec.setContent( new Intent( this ,SecondTab. class )); |
페이지가 로딩되었을때 특정 탭의 내용이 나타날수 있도록 해주고 싶을 때가 있다.
기본은 첫번째 탭인데 2번째 탭을 로딩시 보여주고 싶다면 setCurrentTab(i) 함수를
사용한다. i 는 위에서 언급했듯이 왼쪽탭부터 0 으로 시작한다2 | tabHost.getTabWidget().setCurrentTab( 1 ); |
FirstTab, SecondTab 은 기본 Activity 클래스를 만들어서 넣으면 됩니다.
그리고 AndroidManifest.xml 에 두 Activity 가 포함되어 있어야 됩니다.
<activity android:name=".widget.FirstTab" />
<activity android:name=".widget.SecondTab" />
01 | import android.app.TabActivity; |
02 | import android.content.Intent; |
03 | import android.graphics.Color; |
04 | import android.os.Bundle; |
05 | import android.widget.TabHost; |
06 | import android.widget.TabHost.TabSpec; |
10 | public class TabColor extends TabActivity { |
12 | /** Called when the activity is first created. */ |
14 | public void onCreate(Bundle savedInstanceState) { |
15 | super .onCreate(savedInstanceState); |
16 | setContentView(R.layout.tab_color); |
19 | TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost); |
21 | /** 새로운 탭을 추가하기 위한 TabSpect */ |
22 | TabSpec firstTabSpec = tabHost.newTabSpec( "tid1" ); |
23 | TabSpec secondTabSpec = tabHost.newTabSpec( "tid1" ); |
25 | firstTabSpec.setIndicator( "First Tab Name" , getResources().getDrawable(R.drawable.guitar)); |
26 | firstTabSpec.setContent( new Intent( this ,FirstTab. class )); |
27 | secondTabSpec.setIndicator( "Second Tab Name" , getResources().getDrawable(R.drawable.quicktime)); |
28 | secondTabSpec.setContent( new Intent( this ,SecondTab. class )); |
30 | /** 탭을 TabHost 에 추가한다 */ |
31 | tabHost.addTab(firstTabSpec); |
32 | tabHost.addTab(secondTabSpec); |
35 | tabHost.getTabWidget().getChildAt( 0 ).setBackgroundColor(Color.parseColor( "#534512" )); |
36 | tabHost.getTabWidget().getChildAt( 1 ).setBackgroundColor(Color.parseColor( "#4E4E9C" )); |
39 | tabHost.getTabWidget().setCurrentTab( 1 ); |
tab_color.xml 01 | <? xml version = "1.0" encoding = "utf-8" ?> |
03 | < TabHost android:layout_width = "fill_parent" |
05 | android:id = "@android:id/tabhost" > |
06 | < LinearLayout android:id = "@+id/LinearLayout01" |
07 | android:orientation = "vertical" android:layout_height = "fill_parent" |
08 | android:layout_width = "fill_parent" > |
09 | < TabWidget android:id = "@android:id/tabs" |
10 | android:layout_height = "wrap_content" android:layout_width = "fill_parent" ></ TabWidget > |
11 | < FrameLayout android:id = "@android:id/tabcontent" |
12 | android:layout_height = "fill_parent" android:layout_width = "fill_parent" ></ FrameLayout > |