안드로이드 탭 기본 사용법. [TabWidget, TabHost, TabSpec] (Android Tab)

2017. 3. 13. 20:57


1. 안드로이드 탭(Tab) 위젯

탭(Tab) 위젯은 다양한 UI 프레임워크에서 기본적으로 제공되는 UI 구성요소입니다. 화면에 표시되는 기본 형태는 프레임워크에 따라 차이가 있지만, "여러 페이지로 구성된 UI 레이아웃을 화면의 동일한 영역에 번갈아 표시할 때 사용"하는 것과, "각 페이지의 전환이 탭(Tab) 위젯 안에 있는 탭(버튼 역할)을 통해 수행"된다는 공통점이 있습니다.

UI 프레임워크에서 탭 표시 모양


안드로이드에도 탭(Tab) 위젯을 위한 UI 요소가 제공됩니다. 특히 모바일 기기처럼 작은 화면에서는 여러 페이지를 하나의 영역에 번갈아 가며 표시할 수 있으므로 공간 효율성을 높일 수 있는 장점이 있죠.

2. TabWidget과 TabHost 그리고 FrameLayout.

2.1 TabWidget 클래스 (android.widget.TabWidget)

안드로이드에서 제공되는 탭(Tab) 위젯 기능을 위한 클래스는 TabWidget(android.widget.TabWidget) 클래스입니다.

TabWidget 클래스


TabWidget 클래스에는 탭 위젯 안에 표시되는 탭을 추가하거나, 수정, 삭제하기 위한 함수들이 정의되어 있으며, 해당 함수를 통해 추가된 탭은 탭 위젯의 영역 내에 가로 방향으로 나란히 표시됩니다.

TabWidget 표시 화면


그런데 막상 TabWidget 클래스를 사용하여 탭 위젯 기능을 구현하려고 하면, TabWidget 클래스 단독으로는 탭 기능 구현이 불가능하다는 사실을 발견할 수 있습니다. 그 이유는 바로, 탭 위젯 내부의 탭이 눌려질 때 표시되는 내용을 위한 페이지 화면 때문입니다.


안드로이드의 탭 위젯 구현 방식은 다른 UI 프레임워크와는 조금 다르게, 버튼 역할을 하는 탭(Tab)과 각 탭이 눌려졌을 때 표시될 내용(Content)을 한번에 지정하게끔 만들어져 있습니다. 즉, 탭을 관리하는 TabWidget에 더하여, 내용(Content)으로 표시될 페이지 뷰(View)까지 관리하는 추가적인 요소가 필요하다는 것이죠.


이렇게 TabWidgetTabWidget의 탭 선택에 따라 표시될 내용(Content)을 관리하는 호스트(Host:주인,관리자) 역할을 수행하는 클래스는 바로 TabHost(android.widget.TabHost) 클래스입니다.

2.2 TabHost 클래스 (android.widget.TabHost)

TabHost 클래스는 앞서 설명한대로, 탭 버튼을 표시하는 TabWidget과, 각 탭의 선택에 따라 표시될 페이지 화면을 관리하는 클래스입니다. 안드로이드 탭(Tab) 기능과 관련된 모든 내용을 포함하고 있는 컨테이너(Container) 역할을 수행하는 것이죠.


TabWidget외에, TabHost가 관리하는 페이지 화면은 반드시 FrameLayout을 사용하여 구성해야 합니다. 이는 TabWidget의 탭 선택에 따라 표시될 페이지 화면이 이전 페이지를 완벽히 덮는 형태로 표시되어야 하는, 지극히 당연한 이유 때문이죠.


TabHostTabWidgetFrameLayout이 배치되는 기본 구조는 아래와 같습니다.

TabHost의 TabWidget과 FrameLayout


그리고 TabHost를 구성하는 레이아웃 리소스 XML의 기본 구조는 아래와 같이 작성됩니다.

    <TabHost
        ...>

        <LinearLayout
            ...
            android:orientation="vertical">

            <TabWidget
                ...
                android:id="@android:id/tabs" />

            <FrameLayout
                ...
                android:id="@android:id/tabcontent">

                <!-- TAB CONTENT 1 -->
                    ...

                <!-- TAB CONTENT 2 -->
                    ...

                <!-- TAB CONTENT 2 -->
                    ...

            </FrameLayout>
        </LinearLayout>
    </TabHost>

위의 레이아웃 리소스 XML 코드 중 TabHostTabWidgetFrameLayout을 추가할 때, LinearLayout을 사용한 것에 주의하세요. 클래스 계층 관계를 보면 알겠지만, TabHostFrameLayout에서 상속된, 뷰 그룹으로써의 역할을 수행하는 위젯입니다.

TabHost 클래스


그래서 TabHost의 자식으로 뷰그룹(LinearLayout과 같은)을 사용하지 않고 TabWidgetFrameLayout을 배치하면, 일반적인 상황에서 FrameLayout을 사용할 때 처럼, 추가된 자식들(Children)이 중첩되어버리는 문제가 발생하죠. 이를 해결하기 위해 LinearLayout 사용한 것입니다.

2.3 TabHost 사용 제약 사항.

앞서 설명한 내용을 포함하여 TabHost를 사용할 때 주의해야 할 몇 가지 제약 사항이 있습니다. 주로 레이아웃 리소스 XML과 관련된 내용인데요. 정리하자면 다음과 같습니다.


  1. TabHostFrameLayout을 상속하였으므로, 뷰그룹을 사용하여 자식(Children)들을 배치해야 합니다. (예제에서는 LinearLayout 사용)
  2. TabWidget의 id 속성에는 반드시 "@android:id/tabs" 값을 지정해야 합니다.
  3. TabHost내에서 내용(Contents)을 표시할 곳은 반드시 FrameLayout을 사용해야 합니다.
  4. 내용(Contents) 표시를 위한 FrameLayout의 id 속성 값은 반드시 "@android:id/tabcontent"이어야 합니다.
  5. findViewById() 함수를 통해 TabHost를 설정하는 경우, TabHost의 참조를 가져온 다음 반드시 setup() 함수를 호출해야 합니다. (예제 소스의 [STEP-2]에서 확인)

3. 안드로이드 탭(Tab) 사용하기.

그럼 이제 앱 만들기 예제를 통해 안드로이드 탭(Tab) 위젯을 사용하는 방법에 대해 살펴보겠습니다.


예제에서는, 앞서 설명한 방법대로 TabHost 내에 TabWidgetFrameLayout을 표시합니다. 그리고 TabWidget의 각 탭 버튼이 눌려지면, FrameLayout안에 선언된 자식 뷰를 바꿔가며 표시하도록 만들겠습니다.

예제 화면 레이아웃 구성


3.1 MainActivity 레이아웃 구성.

예제의 첫 번째 단계는 Mainactivity에 표시될 Layout 리소스 XML을 작성하는 것입니다. 이 때 앞에서 언급한 주의사항의 내용에 따라, TabWidget의 "id"가 "@android:id/tabs"이어야 한다는 것과, FrameLayout의 "id"는 "@android:id/tabcontent"이어야 한다는 것에 주의하세요.


그리고 FrameLayout의 자식들(Children)은 LinearLayout을 사용하였습니다.

[STEP-1] "activity_main.xml" - MainActivity의 Layout 리소스 XML.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/content_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.recipes4dev.examples.tabwidgetbasicexample.MainActivity"
    tools:showIn="@layout/activity_main">

    <TabHost
        android:id="@+id/tabHost1"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <!-- TabWidget의 id값이 반드시 "tabs"로 지정되어야 함. -->
            <TabWidget
                android:id="@android:id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <!-- FrameLayout의 id값이 반드시 "tabcontent"로 지정되어야 함. -->
            <FrameLayout
                android:id="@android:id/tabcontent"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <!-- 첫 번째 페이지. content1 -->
                <LinearLayout
                    android:id="@+id/content1"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:background="#8BC34A"
                        android:gravity="center"
                        android:padding="8dp"
                        android:text="TAB CONTENT 1" />

                </LinearLayout>

                <!-- 두 번째 페이지. content2 -->
                <LinearLayout
                    android:id="@+id/content2"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:background="#009688"
                        android:gravity="center"
                        android:padding="8dp"
                        android:text="TAB CONTENT 2" />

                </LinearLayout>

                <!-- 세 번째 페이지. content3 -->
                <LinearLayout
                    android:id="@+id/content3"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:background="#2196F3"
                        android:gravity="center"
                        android:padding="8dp"
                        android:text="TAB CONTENT 3" />

                </LinearLayout>
            </FrameLayout>
        </LinearLayout>
    </TabHost>
</RelativeLayout>

3.2 TabHost에 탭 추가.

이제, TabHost에 탭을 추가하고, 각 탭이 눌려졌을 때 표시될 페이지 뷰에 대한 정보를 추가합니다. 이 과정은 TabHost.TapSpec 클래스의 객체를 만들고, TabHost.addTab()함수를 사용하여 객체를 전달함으로써 수행됩니다.


TabHost.TapSpec을 통해 하나의 탭이 추가되는 과정은 아래와 같습니다.

    // "Tab Spec" 태그(Tag)를 가진 TabSpec 객체 생성.
    TabHost.TabSpec ts = tabHost.newTabSpec("Tab Spec") ;

    // 탭이 눌려졌을 때 FrameLayout에 표시될 Content 뷰에 대한 리소스 id 지정.
    ts.setContent(R.id.content) ;

    // 탭에 표시될 문자열 지정.
    ts.setIndicator("TAB") ;

    // TabHost에 탭 추가.
    tabHost.addTab(ts)  ;

TabHost.TapSpec의 객체를 생성할 때는 new 키워드가 아닌, TabHostnewTabSpec() 함수를 호출해야 한다는 것을 주의하세요. 그리고 newTabSpec() 함수에 전달되는 태그(Tag)는 탭 버튼을 식별할 때 사용되는 값입니다.


위에서 설명한 방법을 사용하여 탭 버튼을 추가하는 예제 소스는 아래와 같습니다.

[STEP-2] "MainActivity.java" - TabHost.TabSpec을 사용하여 탭 추가.
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        // ... 코드 계속

        TabHost tabHost1 = (TabHost) findViewById(R.id.tabHost1) ;
        tabHost1.setup() ;

        // 첫 번째 Tab. (탭 표시 텍스트:"TAB 1"), (페이지 뷰:"content1")
        TabHost.TabSpec ts1 = tabHost1.newTabSpec("Tab Spec 1") ;
        ts1.setContent(R.id.content1) ;
        ts1.setIndicator("TAB 1") ;
        tabHost1.addTab(ts1)  ;

        // 두 번째 Tab. (탭 표시 텍스트:"TAB 2"), (페이지 뷰:"content2")
        TabHost.TabSpec ts2 = tabHost1.newTabSpec("Tab Spec 2") ;
        ts2.setContent(R.id.content2) ;
        ts2.setIndicator("TAB 2") ;
        tabHost1.addTab(ts2) ;

        // 세 번째 Tab. (탭 표시 텍스트:"TAB 3"), (페이지 뷰:"content3")
        TabHost.TabSpec ts3 = tabHost1.newTabSpec("Tab Spec 3") ;
        ts3.setContent(R.id.content3) ;
        ts3.setIndicator("TAB 3") ;
        tabHost1.addTab(ts3) ;
    }
}

예제의 내용 중 findViewById() 함수를 사용해 TabHost의 참조를 가져온 다음, TabHost.setup() 함수를 호출한 것에 주의하세요. 만약 setup() 함수를 호출하지 않으면 TabWidget이 정상적으로 표시되지 않습니다.

TabHost의 setup 함수


이제 안드로이드 탭 예제 작성은 완료되었습니다.

4. 안드로이드 탭(Tab) 예제 실행 화면.

예제를 실행하면, 아래 그림과 같이 안드로이드 탭 화면이 표시됩니다.

안드로이드 탭 예제 실행 화면 1


각 탭 버튼을 선택하면, 버튼 선택에 따라 페이지 뷰가 바뀌는 것을 확인할 수 있습니다.

안드로이드 탭 예제 실행 화면 1


5. 참고

.END.


ANDROID 프로그래밍/TAB