안드로이드 프레임레이아웃. (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 , , , , , , ,

  1. Blog Icon
    감사

    믿고 보는 뽀따님 강좌!

  2. 믿고 보기엔 아직 내용이 많이 허술합니다.
    꼼꼼하게 살피려고는 하나, 부족하네요.
    앞으로 더 믿고 볼 수 있도록 준비하겠습니다.

    감사합니다.

  3. 도움 많이 얻었습니다. 알찬 글 감사합니다!!

  4. 방문해 주셔서 감사합니다!!

  5. Blog Icon
    코린이

    안녕하세요!
    linear layout에서 시간표를 col을 짜는 중인데 이걸 곂치게하는데에도 쓸 수 있을까요?
    마진을 줘서 시간표를 짜는데 마진이 곂쳐서 생각되지 않고 위에 있는 수업을 기준으로 마진이 잡혀서 훨씬 아래로 가버려서요.

  6. 죄송하게도, 질문만으로는 어떤 상황인지 잘 이해가 되질 않습니다.

    상황에 대한, 조금 더 구체적인 설명이 필요할 것 같아요.

    시간표를 위한 레이아웃을 구성하는 건 알겠는데요,

    1. "시간표를 col을 짜는 중"이 무슨 말이지?
    2. "곂치게하는데에도 쓸 수"있다는 게 뭘 겹치게 한다는 말인지?
    3. "마진이 곂쳐서 생각되지 않고"에서 마진은 왜 곂(?)치고, 뭐가 생각되지 않는건지..?
    4. "수업을 기준으로 마진이 잡히"는 것에서 수업은 어떤 요소를 말하는지..

    제가 이해를 못해서, 조금 더 자세한 설명이 필요할 것 같습니다.

    조금은 더 상황을 잘 정리해서 질문글 남겨주세요.
    그러면 조금 더 도움드리기가 쉬울 것 같습니다.

    감사합니다.

  7. Blog Icon
    쪼꼬미

    뽀따님의 지식을 제 머리에 담고싶어서 오늘도 정독하다가 댓글남기구 갑니당ㅇㅇㅇㅇ
    오늘도 감사해요 감기조심하세용!

  8. 에고.. 제 머리에 있는 지식은 너무 보잘 것 없어서 덜어드릴 것도 없네요. ㅜㅜ

    그래도 열심히 공부하는 그 열정에 박수와 응원 보냅니다.

    추운 겨울 감기 조심하세요.
    감사합니다.

  9. Blog Icon

    비밀댓글입니다

  10. Blog Icon
    주승

    앱을 공부하고 있는 학생입니다. 자바 언어는 완전 처음이고 안드로이드 스튜디오 자체도 처음 설치한 초보에게 글쓴이님의 이 게시글들이 너무 감사하네요. 쭉 읽으면서 공부하다가 너무 감사해서 글 남깁니다.

  11. 좀 지난 내용들도 많고, 부족함도 많은 블로그를 방문해주셔서 정말 감사드려요. 이렇게 댓글까지 남겨주시고.. ^^

    아무쪼록, 제가 올린 글들이 앱 개발하는데 도움되셨으면 좋겠습니다.

    감사합니다.

  12. Blog Icon
    jj

    정리가 정말 잘 되어 있네요 감사합니다!

  13. 방문해주시고, 격려의 댓글 남겨주셔서 감사합니다.

  14. 졸업 예정인 학생인데, 어쩌다 안드로이드 개발에 접하게 되어서
    이것 저것 많이 구글링 해보게 되었는데 뽀따님 블로그는
    정리가 정말정말 잘 되어있어서 항상 도움 받고 갑니다.
    저도 공부한 내용을 정리하고 싶어서 블로그를 시작했는데
    이렇게 많은 양의 내용을 손수 정리해오셨다는게 대단하고 존경심까지 들어요!
    뽀따님 글을 참고해서 제 블로그에도 공부내용 정리하고 싶은데 가능할까요?
    출처와 url 남기겠습니다 !
    좋은 글 감사합니다.

  15. 내용 일부와 출처 남기시는 건 괜찮습니다.

    도움이 되셨다니 다행이네요.
    격려의 글 남겨주셔서 감사합니다.