안드로이드 프레임레이아웃. (Android FrameLayout)

2017. 5. 15. 15:29


1. 안드로이드 FrameLayout

[안드로이드 리니어레이아웃 (Android LinearLayout)]과 [안드로이드 렐러티브레이아웃 (Android RelativeLayout)]에서 봤듯이 Layout 클래스는 자신만의 배치 기능에 따라, Layout에 포함된 다양한 뷰(View) 위젯을 화면에 정렬할 때 사용합니다. 그런데 화면에 뷰(View) 위젯을 표시함에 있어 주 목적이 다른 Layout 클래스가 하나 있습니다. 바로 FrameLayout 입니다.


FrameLayout은 자식(Children)으로 추가된 여러 뷰(View) 위젯들 중 하나를 Layout의 전면에 표시할 때 사용하는 클래스입니다. "Frame"이라는 단어의 의미가 "액자"라는 것을 떠올려보면, FrameLayout의 동작 방식을 좀 더 쉽게 이해할 수 있죠.

FrameLayout에서 Frame의 의미


보통 "액자(Frame)"에는 사진을 끼워서 사용합니다. 그리고 분위기(?) 또는 취향(?)에 따라 "액자(Frame)"에 있는 사진을 빼고, 다른 사진을 끼워서 사용하죠. FrameLayout의 주 용도는, 바로 이 "액자(Frame)"처럼, 화면에 표시될 뷰(View)를 바꿔가면서 표시하기 위함입니다.


그런데 FrameLayout이 하나의 자식(Child) 뷰 위젯을 전면에 표시할 때 사용된다고 해도, 오직 하나의 자식(Child) 뷰 위젯만 가질 수 있다거나, 전면에 표시되는 뷰(View) 외의 다른 뷰(View)가 아예 표시조차 되지 않는 것은 아닙니다. 보통 "액자(Frame)"에도 액자 크기만한 큰 사진 앞에 작은 사진들을 끼워서 사용하는 경우가 있죠. 마찬가지로 FrameLayout에도 다양한 크기의 뷰(View) 위젯들을 추가할 수 있습니다.


최초 FrameLayout이 화면에 그려질 때 전면에 표시되는 뷰(View) 위젯은 레이아웃 XML 코드의 가장 마지막에 추가된 뷰(View) 위젯입니다. 즉, "액자(Frame)"에 그림을 끼우면 젤 앞에 끼워진 그림이 전면에 보여지듯이, FrameLayout에 가장 마지막으로 추가된 자식(Children) 뷰 위젯이 화면의 전면에 표시되는 것이죠. 그리고 FrameLayout에 추가되는 자식(Children)들은 뒤에서부터 앞으로 쌓이면서 그려지기 때문에, 전면에 표시되는 뷰(View)의 크기가 다른 뷰(View)보다 작으면, 먼저 추가된 뷰(View)의 일부가 화면에 보여지게 됩니다.

FrameLayout에서 표시되는 뷰는 가장 마지막 뷰


하지만 안드로이드에서는, 여러 뷰(View)를 동시에 표시해야 하는 명확한 의도가 없는 한, FrameLayout이 오직 하나의 자식(Child) 뷰 위젯만을 표시하게 만들도록 권고하고 있습니다. 자식(Children) 뷰들이 서로 겹치지 않으면서, 다양한 화면 크기에 따라 스케일될 수 있는(scalable) UI를 구성하기가 어렵기 때문입니다.

FrameLayout에서는 오직 하나의 자식 뷰 위젯만 표시하도록 권고


그리고 FrameLayout의 layout_width와 layout_height 값이 "wrap_content"인 경우, FrameLayout의 크기는, 자신에게 포함된 자식(Children) 뷰 위젯 중에서 가장 큰 뷰(View) 위젯에 맞춰집니다.

2. FrameLayout 사용 방법

2.1 FrameLayout 기본 사용법

FrameLayout에 자식(Children) 뷰 위젯을 표시하는 방법은 간단합니다. "<FrameLayout>"과 "</FrameLayout>"사이에 뷰(View) 위젯을 선언하면 됩니다.

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:background="#4CAF50"
            android:id="@+id/text1"
            android:text="TEXT1" />

    </FrameLayout>

FrameLayout 기본 사용 예제 1


앞서 잠시 언급한대로, FrameLayout에 여러 개의 자식(Children)을 추가하면, 기본적으로 가장 마지막에 추가된 뷰(View)가 가장 전면에 표시됩니다.

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="48sp"
            android:background="#4CAF50"
            android:id="@+id/text1"
            android:text="TEXT1" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="36sp"
            android:background="#FF9800"
            android:id="@+id/text2"
            android:text="TEXT2" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:background="#009688"
            android:id="@+id/text3"
            android:text="TEXT3" />

    </FrameLayout>

FrameLayout 기본 사용 예제 2


2.2 FrameLayout 내 자식(Children) 뷰 위젯의 위치 조절.

앞선 예제에서 봤듯이, FrameLayout에 추가된 뷰(View) 위젯은 기본적으로 FrameLayout의 왼쪽(Left), 위(Top)를 기준으로 정렬됩니다. 그런데 이러한 정렬 기준은 FrameLayout의 각 자식(Children) 뷰 위젯에 "layout_gravity" 속성 값을 지정하여 변경할 수 있습니다.

  * android:layout_gravity - 자신이 속한 부모 Layout내 자신의 정렬 위치 값 지정.
        > 부모 Layout 내에서 x축(좌/우)과 y축(상/하)을 기준으로 정렬.
        > 아래 값들 중에서 하나 이상의 값을 '|' 기호로 혼합하여 사용.
          -. top (0x30)               : 부모 Layout 안에서, 위쪽에 위치.
          -. bottom (0x50)            : 부모 Layout 안에서, 아래쪽에 위치.
          -. left (0x03)              : 부모 Layout 안에서, 왼쪽에 위치.
          -. right (0x05)             : 부모 Layout 안에서, 오른쪽에 위치.
          -. center_vertical (0x10)   : 세로 기준으로 가운데 위치.
          -. fill_vertical (0x70)     : 세로 방향으로 가득 채움.
          -. center_horizontal (0x01) : 가로 기준으로 가운데 위치.
          -. fill_horizontal (0x07)   : 가로 방향으로 가득 채움.
          -. center (0x11)            : 가로, 세로 기준으로 가운데 정렬.
          -. fill (0x77)              : 가로, 세로 방향으로 가득 채움.
          -. clip_vertical (0x80)     : 세로 기준으로 Layout을 넘어서는 영역 자르기.
          -. clip_horizontal (0x08)   : 가로 기준으로 Layout를 넘어서는 영역 자르기.
          -. start (0x00800003)       : 부모 Layout 안에서, 시작 위치에 정렬.
          -. end (0x00800005)         : 부모 Layout 안에서, 끝 위치에 정렬.
        > 기본 정렬은 가로 방향 start, 세로 방향 top.

각 속성 값에 따른 표시 내용은 아래와 같습니다.

FrameLayout에서 layout_gravity 속성 값 표시 내용


참고로, 현재 fill 관련 속성 값(fill_hotizontal, fill_vertical, fill) 및 clip 관련 속성 값(clip_horizontal, clip_vertical)은 FrameLayout에서 적용되지 않는 것으로 파악됩니다. (하지만, 추가적인 내용이 파악되면 내용을 보충하여 본문에 기록하겠습니다.)


FrameLayout에 포함된 자식(Children) 뷰 위젯에 각각 다른 gravity를 적용하여 FrameLayout내 다른 영역에 표시되도록 만들 수 있습니다.

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#4CAF50"
            android:textSize="24sp"
            android:layout_gravity="left|top"
            android:text="TEXT 1" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#FF9800"
            android:textSize="24sp"
            android:layout_gravity="center"
            android:text="TEXT 2" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#009688"
            android:textSize="24sp"
            android:layout_gravity="right|bottom"
            android:text="TEXT 3" />

    </FrameLayout>

FrameLayout에서 layout_gravity 예제


3. FrameLayout에 표시될 자식(Children) 뷰 변경하기

FrameLayout에 표시될 뷰(View)를 변경하는 방법은 크게 두 가지가 있습니다. FrameLayout이 무조건 하나의 자식(Child) 뷰 위젯만 가지도록 만드는 방법과 FrameLayout에 포함된 자식(Children) 뷰 위젯들의 보이기(visibility) 속성을 사용하여, 오직 하나의 뷰(View)만 화면에 표시되도록 만드는 것입니다.

3.1 FrameLayout에 뷰 추가(addView()) 또는 뷰 삭제(removeView()).

FrameLayout에 표시될 뷰(View)를 결정하는 가장 직관적인 방법은, FrameLayout이 오직 하나의 자식(Child) 뷰만 가지도록 만드는 것입니다. 만약 다른 뷰(View)가 표시되어야 한다면, 기존 뷰(View)는 없애고 새로운 뷰(View)를 추가하는 것이죠. 마치 "액자(Frame)"의 사진을 바꿔 끼우듯이 말이죠.


이는 FrameLayout의 addView() 함수와 removeView() 또는 removeViewAt() 함수를 사용하여 수행할 수 있습니다.


아래는 addView()와 removeViewAt() 함수를 사용하여 FrameLayout에 표시될 자식(Child) 뷰 위젯을 변경하는 예제입니다.

    private void changeView(int index) {

        frame.removeViewAt(0) ;

        switch (index) {
            case 0 :
                frame.addView(textView1) ;
                break ;
            case 1 :
                frame.addView(textView2) ;
                break ;
            case 2 :
                frame.addView(textView3) ;
                break ;
        }
    }

3.2 FrameLayout에 추가된 자식(Children) 뷰의 보이기(Visibility) 속성 사용.

두 번째 방법은 미리 FrameLayout에 여러 자식(Children) 뷰 위젯들을 추가해두고, 자식(Children) 뷰 위젯의 visibility 속성을 사용하여 화면에 표시될 뷰(View)를 변경하는 방법입니다.


레이아웃 XML 코드를 작성할 때, 최초 화면에 표시될 뷰(View)만 visibility 속성 값을 "visible"로 지정하고, 나머지 뷰(View)는 "invisible"로 지정합니다.

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/frame">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/text1"
            android:visibility="visible"
            android:text="TEXT 1" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/text2"
            android:visibility="invisible"
            android:text="TEXT 2" />

    </FrameLayout>

자바 코드에서는, 뷰(View)의 참조를 가져온 다음, 뷰(View)의 setVisibility() 함수를 사용하여 화면 표시 여부를 결정할 수 있습니다.

    private void changeView(int index) {
        TextView textView1 = (TextView) findViewById(R.id.text1) ;
        TextView textView2 = (TextView) findViewById(R.id.text2) ;

        switch (index) {
            case 0 :
                textView1.setVisibility(View.VISIBLE) ;
                textView2.setVisibility(View.INVISIBLE) ;
                break ;
            case 1 :
                textView1.setVisibility(View.INVISIBLE) ;
                textView2.setVisibility(View.VISIBLE) ;
                break ;
        }
    }

4. FrameLayout이 사용되는 UI

앞서 FrameLayout이 오직 하나의 자식(Child) 뷰 위젯만을 표시하는데 사용된다고 설명했습니다. 그러므로 안드로이드 SDK에서 FrameLayout이 사용되는 곳을 보면, 하나의 Layout 영역에 여러 종류의 뷰(View)를 번갈아가며 표시하는데 사용되는 것을 확인할 수 있습니다.

4.1 Fragment의 컨테이너로써의 FrameLayout

Fragment는 화면을 여러 모듈 단위로 구성할 수 있도록 만들어주는 기능입니다. 특히, 화면 크기에 따라 동적 변화가 필요한 UI를 구성하기에 적합한 요소인데요, 이 Fragment가 표시되는 컨테이너(Container)로써 FrameLayout이 주로 사용됩니다.


Fragment에 대한 자세한 설명은 [안드로이드 프래그먼트 기본 사용법 (Android Fragment)]을 참고하시기 바랍니다.

4.2 탭 호스트(TabHost)의 내용(Content)을 위한 페이지를 표시하는 FrameLayout

탭 호스트(TabHost)는 여러 페이지로 구성된 화면을 동일한 영역에 번갈아 표시할 때 사용되는 UI 구성요소입니다. 탭 호스트(TabHost)는 탭(Tab) 버튼을 포함하는 탭 위젯(TabWidget)과, 버튼 선택에 따라 그 내용을 표시하는 페이지로 구성되는데요. 바로 이 "페이지가 표시되는 영역"에 FrameLayout이 사용됩니다.


안드로이드 탭(Android Tab)에 대한 자세한 설명은 [안드로이드 탭 기본 사용법]에서 확인할 수 있습니다.

5. 참고.

.END.


ANDROID 프로그래밍/LAYOUT