IT_Programming/Android_Java

Android GridLayout Tutorial

JJun ™ 2014. 8. 5. 23:59

 


 출처: http://aroundck.tistory.com/2746#recentTrackback


 

 

점점 화면에 표시하는 UI 가 많아지면서 Layout 의 중첩 ( overdrawing ) 으로 성능 영향이 생기기 시작했다.

RelativeLayout 을 통해 이를 방지하는 tutorial 혹은 guide 들이 많이 나오기는 했지만,

이는 xml 코드(?) 를 엄청 복잡하게 만들고, 유지보수 또한 어려워지기 쉽상이다.


그래서 ICS 부터 GridLayout 이라는 새로운 layout 이 도입되었다.

물론 support-v7 를 통해 ICS 이전 버전에서도 GridLayout 을 이용할 수 있다.


http://developer.android.com/reference/android/widget/GridLayout.html


GridLayout 은 Web 의 Table 을 잘 다뤄본 사람에게는 친숙할 것이다.


GridLayout 의 xml 주요 속성들은...


android:orientation="horizontal | vertical"

android:columnCount="5" // 최대 갯수

android:rowCount="5" // 최대 갯수

android:alignmentMode="alignBounds | alignMargins"

android:columnOrderPreserved="true | false" // 열 인덱스 오름차순 배치

android:rowOrderPreserved="true | false" // 행 인덱스 오름차순 배치

android:userDefaultMargins="true | false" // 기본 마진 사용여부.



GridLayout ChildView 의 xml 속성 ( GridLayout.LayoutParams )


android:layout_column="3" // 열 index

android:layout_row="3" // 행 index

android:layout_columnSpan="2"

android:layout_rowSpan="2"

android:layout_gravity="center" 


소스 출처 : http://developer.samsung.com/android/technical-docs/GridLayout-in-Android


<?xml version="1.0" encoding="utf-8"?>

<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:columnCount="4"

    android:rowCount="4" >


    <TextView

        style="@style/textViewStyle"

        android:text=" R 1, C 1 " />

    <TextView

        style="@style/textViewStyle"

        android:text=" R 1, C 2 " />

    <TextView

        style="@style/textViewStyle"

        android:layout_gravity="fill"

        android:layout_rowSpan="2"

        android:gravity="center"

        android:text=" R 1, C 3 " />

    <TextView

        style="@style/textViewStyle"

        android:text=" R 1, C 4 " />

    <TextView

        style="@style/textViewStyle"

        android:text=" R 2, C 1 " />

    <TextView

        style="@style/textViewStyle"

        android:text=" R 2, C 2 " />

    <TextView

        style="@style/textViewStyle"

        android:text=" R 2, C 4 " />

    <TextView

        style="@style/textViewStyle"

        android:text=" R 3, C 1 " />

    <TextView

        style="@style/textViewStyle"

        android:text=" R 3, C 2 " />

    <TextView

        style="@style/textViewStyle"

        android:layout_gravity="fill_horizontal"

        android:text=" R 3, C 3 modify " />

    <TextView

        style="@style/textViewStyle"

        android:text=" R 3, C 4 " />

    <TextView

        style="@style/textViewStyle"

        android:text=" R 4, C 1 " />

    <TextView

        style="@style/textViewStyle"

        android:text=" R 4, C 2 " />

    <TextView

        style="@style/textViewStyle"

        android:layout_gravity="fill_horizontal"

        android:text=" R 4, C 3 " />

    <TextView

        style="@style/textViewStyle"

        android:text=" R 4, C 4 " />

</GridLayout>


 

 


 

 

 

GridLayout 

 

GridLayout

격자 모양의 표을 만들 수 있는 레이아웃.

 

GridLayout은 API 14(안드로이드 4.0)부터 사용 가능하기 때문에 AndroidManifest.xml의 minSdkVersion을 14이상으로 설정해줘야 사용 가능합니다.

이하 버전일 경우 인스톨이 되지 않고 에러가 납니다. 인스톨이 되었어도 기능사용시 에러가 날 수 있습니다.

   

AndroidManifest.xml

<uses-sdk

android:minSdkVersion="14"

android:targetSdkVersion="19" />

   

   

GridLayout 태그에 지정하는 속성

속성

설명

orientation

배치의 방향을 지정.

가로(vertical) 우선, 세로(horizontal) 우선으로 지정할 수 있으며 디폴트는 horizontal

columnCount

최대 열 개수를 지정.

한 행이 이 개수를 초과하면 아래 행으로 자동 개행.

rowCount

최대 행 개수를 지정.

한 열이 이 개수를 초과하면 오른쪽 열로 자동 개행.

alignmentMode

차일드 정렬의 기준을 지정.

alignBounds이면 차일드의 외곽을 기준으로 하며

alignMargins이면 마진을 기준으로 합니다.

디폴트 alignMargins.

columnOrderPreserved

열의 경계를 인덱스의 오름차순으로 배치

rowOrderPreserved

행의 경계를 인덱스의 오름차순으로 배치

useDefaultMargins

차일드 뷰의 레이아웃에 별다른 지정이 없으면 차일드의 속성을 참조하여 계산한 디폴트 마진을 사용합니다.

이 값이 false이면 마진은 0으로 처리되어 차일드끼리 밀착합니다.

   

   

GridLayout 하위 태그에 지정하는 속성

속성

설명

layout_column

차일드가 배치될 셀의 열 좌표를 지정.

디폴트 UNDEFIED 차일드 순서에 따라 자동 계산

layout_row

차일드가 배치될 셀의 행 좌표를 지정.

디폴트 UNDEFIED 차일드 순서에 따라 자동 계산

layout_columnSpan

차일드가 차지할 열 수를 지정.

디폴트는 1

layout_rowSpan

차일드가 차지할 행 수를 지정.

디폴트는 1

layout_gravity

열 내에서의 차일드 정렬 방식을 지정.

디폴트 LEFT|BASELINE

 

 

 


 

 

 

 출처: http://cafe369.daum.net/_c21_/bbs_search_read?grpid=1MWA2&fldid=aAfL&contentval=0002nzzzzzzzzzzzzzzzzzzzzzzzzz&nenc=&fenc=&q=CLIP&nil_profile=cafetop&nil_menu=sch_updw

 

 

GridLayout은 API14부터 공개가 되었으나 아직 서적이나 인터넷에 상세한 설명이 존재하지 않습니다.

GridLayout은 LinearLayout, RelativeLayout, FrameLayout, TableLayout, AbsoluteLayout 과 함께 레이아웃이라고

명명되는 뷰그룹중 하나입니다. 그 만큼 안드로이드 측에서는 야심차게 내놓은 뷰그룹이라고 할 수 있겠죠. ^^


● GridLayout과 LayoutParams


시작에 앞서 GridLayout은 TableLayout의 단점을 보완하고 LinearLayout과 RelativeLayout, FrameLayout의 장점을 포함한 뷰그룹이라고 안드로이드 개발자 사이트에 기재되어 있다. 뿐만 아니라 여러 개의 뷰그룹을 중첩해서 사용할 필요가 없어 다른 뷰그룹 보다 메모리 사용량이 적고 성능이 좋으므로
적극 사용을 권장하고 있다. 
 

참고 사이트

http://android-developers.blogspot.kr/2011/11/new-layout-widgets-space-and-gridlayout.html


하지만 개인적으로 GridLayout을  활용하여 개발해 본 결과 결코 큰 장점을 발견하지 못했다. 

오히려 사용이 아주 어렵고 불편하며, 복잡한 레이아웃을 구성하려면 시간이 많이 걸린다. 

그러므로 처음부터 GridLayout을 써야만 최적화된 레이아웃이다라는 편견을 가지지 말도록 하자. 

뷰그룹은 상황에 맞도록 적절히 섞어서 활용하는 것이 바람직하다. 


GridLayout은 API 레벨 14 부터 사용이 가능하니 주의하도록 하자

(안드로이드에서 제공하는 support v7 라이브러리를 이용하면 이하 버전에서도 사용이 가능하다. 

 마지막 부분에 support v7 라이브러리를 사용법에 대해서 설명한다).

 

GridLayout은 TableLayout의 구조적인 문제를 해결하기 위해 단독 뷰그룹 만으로 

테이블 형태의 레이아웃을 제공한다(TableLayout과 같이 여러 개의 TableRow을 포함할 필요가 없다)

 

그림 1 GridLayout 사용을 위한 minSdkVersion 조정하기

혹시 그림과 같이 AndroidManifest.xml에 android:minSdkVersion이 10으로 되어 있다면 14로 수정하도록 하자.

시작에 앞서 예제를 통해 간단히 GridLayout 에 대해서 살펴보자.

 

 

그림 2 간단히 GridLayout의 구조 살펴보기

 

TableLayout과는 달리 하나의 GridLayout만으로 테이블 형태의 레이아웃을 만들었다. 

차이가 있다면 미리 행과 열의 개수를 지정해 두는 점이다. 

이제 행과 열을 어떻게 제어하는지 세부 속성들을 들여다 보자.


■ GridLayout 의 기본 속성


GridLayout의 속성들

XML 속성값

의미

orientation

각 셀을 채우는 순서를 설정한다.

- horizontal : 수평 기준으로 자식 뷰를 채워 나간다.

-vertical : 수직 기준으로 자식 뷰를 채워 나간다.

rowCount

전체 행의 개수를 지정한다.

columnCount

전체 열의 개수를 지정한다.

alignmentMode

가장 여백이 큰 자식 뷰 기준으로 정렬 기준을 지정

alignBounds : 가장 여백이 큰 자식 뷰의 외곽을 중심으로 정렬

alignMargins : 여백을 정렬 기준에서 제외하고 정렬

rowOrderPreserved

false 값은 행의 순서를 무시할 수 있다.

columnOrderPreserved

false 값은 열의 순서를 무시할 수 있다.

useDefaultMargins

기본적으로 각 셀의 상///우 여백을 준다.

 


 

 

- orientation, rowCount, columnCount 속성

 

본 3가지 속성에 대해서 예제를 통해 이해해 보자.

 

그림 3 GridLayout의 orientation, rowCount, columnCount 속성 

orientation은 뷰들이 배치될 방향을 결정한다. 

horizontal 속성 값은 수평 방향으로 좌측에서 우측으로 배치되며, 

vertical은 수직 방향으로 위에서 아래의 순으로 배치된다. 

rowCout와 columnCount 속성은 배치될 행과 열의 수를 말한다. 

 

그런데 예제에서 rowCount, columnCount 속성 값을 각각 100으로 주고 있지만 전혀 적용되고 있지 않다. 

그 이유를 아래의 그림으로 이해해 보자. 


그림 4 GridLayout의 orientation, rowCount, columnCount 속성의 연관 관계  

orientation 속성 값이 수평 배열인 경우 행의 개수는 의미가 없고 수직 배열인 경우 열의 개수는 의미가 없다. 

GridLayout은 자식 뷰를 추가할 수록 계속 행 혹은 열이 계속 늘어나는 구조이기 때문이다. 

그러므로 수평 배열인 경우 수평 방향으로 추가될 열의 개수만 제한하면 되고, 

수직 배열인 경우 수직 방향으로 추가될 행의 개수만 제한하면 된다. 

이러한 방식은 여러 개의 중첩 뷰그룹을 사용해야 하는 LinearLayout과 TableLayout의 단점을

보완한 점이라고 볼 수 있다. 


 

<잠깐만!!!>

 

첫 번째 의견 GridLayout의 부족한 점

 

TableLayout에는 있으나 GridLayout에는 없는 것들

 

 특정 열을 숨기는 collapseColumns 속성이 없다.

열 공간이 부족할 때 특정 열의 공간을 최대한 줄이는 shrinkColumns 속성이 없다.

열 공간이 남을 때 특정 열의 공간을 늘여서 채우는 stretchColumns 속성이 없다.

 

위의 3가지는 TableLayout 중요한 속성이다. 그러므로 GridLayout TableLayout의 중첩된 구조 보다는 장점을 가질 수 있으나 TableLayout을 대체할 수는 없다.

 


 

- alignmentMode 속성

 

alignmentMode 속성은 가장 너비가 큰 자식 뷰 기준으로 정렬 여부를 결정한다

이 때 자식 뷰의 여백에 정렬을 맞출지를 결정하는 속성 값 두 가지가 존재한다

alignMargins는 여백을 무시하고 정렬하는 값이며alignBounds는 여백을 포함하여 정렬한다. 

아래의 예제로 쉽게 이해해 보자.

그림 5 GridLayout alignmentMode 속성 


alignBounds 속성의 경우 여백 정보까지 정렬의 기준이 되는 것을 알 수 있다. 


 

- columnOrderPreserved, rowOrderPreserved 속성


columnOrderPreserved 속성은 열의 순서를 무시할 수 있으며, 

rowOrderPreserved 속성은 행의 순서를 무시할 수 있다. 예제를 통해 이해해 보자

그림 6 GridLayout의 columnOrderPreserved 속성 활성화 

 

예제에서 배우지 않은 layout_row와 layout_column 속성이 나온다. 

이 값은 특정 뷰의 행과 열의 위치를 강제로 지정할 수 있는 속성이라는 것만 이해하자.

GridLayout의 LayoutParams 속성에서 상세히 설명한다. 

그림과 같이 공간이 부족해서 0열을 시작으로 2,3열이 GridLayout 영역을 벗어났다.

다음 예제를 살펴보자.


그림 7 GridLayout의 columnOrderPreserved 속성 비활성화   

 

columnOrderPreserved 속성을 false로 주면 열의 순서를 무시할 수 있다고 했다. 

결과 화면을 보면 아무 뷰도 삽입되지 않은 2열을 기준으로 3열이 1열을 덮고 있다. 

즉 1열을 3열이 열 순서를 어기고 덮는다는 속성이 적용된 것이다. 아래의 그림으로 좀더 확실히 이해해 보자.

 

그림 8 GridLayout의 columnOrderPreserved, rowOrderPreserved 속성의 의미  

이 속성들은 꼭 아무 뷰도 삽입되지 않은 기준 열 혹은 기준 행이 필요하며, 

보이지 않았던 행/열이 순서를 무시하고 보이는 행/열을 덮는다는 것이다. 


<잠깐만!!!>

 

두 번째 의견 GridLayout의 부족한 점

  

columnOrderPreserved, rowOrderPreserved 속성은 매우 이해하기 어렵다. 분명GridLayout만을 사용해서
다양한 화면 구성을 위해서는 꼭 필요한 속성이다
. 하지만 직접 활용해보면, 너무나도 불편해서 FrameLayout 이나 RelativeLayout등의 다른 뷰그룹이 그리워 질 것이다. 여러분이 본 사용 하면서 너무 이해하기 어렵더라도
괴로워하지 말자
. 나 역시 GridLayout 만 집필하는데 매우 많은 시간이 걸렸고 어려웠다.

 

 

계속해서 rowOrderPreserved 속성도 예제를 통해 확인해 보자.

 

그림 9 GridLayout의 rowOrderPreserved 속성   

 

보이지 않았던 4행이 아무것도 삽입되지 않은 3행을 기준으로 2행을 덮고 있다. 

기준 행이 존재하지 않으면 본 속성은 동작하지 않는다.

 


 

- useDefaultMargins 속성

 

본 속성은 모든 셀에 상/하/좌/우 여백을 준다. 

여백의 수치는 기본으로 8dp라는 값이 시스템에 정의되어 있다. 

예제를 통해 확인해 보자.

 

그림 10 GridLayout의 useDefaultMargins 속성 

 

useDefaultMargins 값을 true로 설정하면 8dp의 여백이 생기는 것이 확인되었다. 

 

 

<잠깐만!!!>

 

세 번째 의견 GridLayout의 부족한 점

 

useDefaultMargins 값은 사용자가 변경할 수 없다. 시스템에 정의된 값만을 사용할 수 있는 것이다. 
개발자들의 의도에 따라 모든 셀의 여백을 지정해 주는 것이 아니라면 본 속성은 너무 제한적이며
유연하지 않기 때문에 거의 사용되지 않을 수 밖에 없다
.

 



■ GridLayout LayoutParams의 기본 속성


그림 11 GridLayout의 LayoutParams 속성 


 

GridLayout LayoutParams 속성들

XML 속성값

의미

layout_gravity

셀 영역 내 자식 뷰의 중력 방향을 설정한다.

layout_row

특정 자식 뷰의 행 위치를 설정한다.

layout_column

특정 자식 뷰의 열 위치를 설정한다.

layout_rowSpan

특정 자식 뷰의 행 위치에서 병합할 셀 개수를 지정한다.

layout_columnSpan

특정 자식 뷰의 열 위치에서 병합할 셀 개수를 지정한다.

 


 

- layout_gravity 속성

 

layout_gravity 속성 자식 뷰의 중력 방향을 결정할 수 있다. 

본 속성은 이미 다른 뷰그룹을 배우면서 익숙해져 있을 것이다. 예제를 통해 확인해 보자.

 

그림 12 GridLayout LayoutParams의 layout_gravity 속성  

 

예제를 보면 자신의 셀 공간 내에서 중력방향 값들이 작동하는 것을 알 수 있다. 

다양한 속성 값들이 적용된 결과를 아래의 그림으로 확인해 보자.

 

그림 13 GridLayout LayoutParams의 layout_gravity 다양한 속성 값  

대부분 속성값들은 이미 다른 뷰그룹에서 배웠기 때문에 이해가 될 것이다. 

하지만 특별한 속성값이 3가지 존재한다. 

 

 fill_horizontal : 수평 셀의 영역에 뷰의 크기를 가득 채운다.

fill_vertical : 수직 셀의 영역에 뷰의 크기를 가득 채운다.

fill : 수평/수직 셀의 영역에 뷰의 크기를 가득 채운다.


GridLayout에서는 셀을 가득 채울 수 있는 유연한 크기 설정 방법이 필요하며,

그 기능을 layout_gravity에서 제공하는 것을 기억하자. 


참고로 자식의 뷰의 크기를 결정하는 layout_width와 layout_height 속성에 대해서 잘 알고 있을 것이다. 

GridLayout에서는 이 두 가지 속성 값을 적어주지 않아도 동작하며, 자식 뷰들은 기본적으로 모든 크기가
wrap_content가 된다. 
만일 부모 뷰그룹 크기를 따르는 match_parent 값을 주게 되면 한 셀의 크기가
부모의 크기가 되어 대부분 화면을 벗어날 것이다. 
그러므로 match_parent 속성을 주어야 할 일이 거의 없다.

 


 

- layout_row, layout_column 속성

 

원하는 행과 열에 자식 뷰를 배치할 수 있는 속성이다.

TableLayout의 경우 자식 뷰의 행 위치를 설정할 수 없었다. 

그러므로 해당 속성은 GridLayout만의 장점이라고 할 수 있다.

layout_row는 행의 위치를 결정하며, layout_column는 열의 위치를 결정한다.

예제를 통해 layout_row 속성에 대해서 알아보자. 


그림 14 GridLayout LayoutParams의 layout_row 속성  

 

예제에서 자식 뷰 View2를 3행으로 설정 및 적용된 것을 볼 수 있다. 

중요한 점은 강제로 행 위치가 결정된 자식 뷰부터 다음에 추가되는 자식 뷰들이 이어서 배치된다는 것이다. 


다음은 layout_column 속성에 대해서 알아보자. 


그림 15 GridLayout LayoutParams의 layout_column 속성  

 

예제에서 자식 뷰 View2를 3열로 설정 및 적용된 것을 볼 수 있다. 

강제로 열 위치가 결정된 자식 뷰 역시 다음에 추가되는 자식 뷰들이 이어서 배치된다.

 


 

- layout_rowSpan, layout_columnSpan 속성

 

본 속성들은 행 혹은 열을 병합할 수 있다. 

layout_rowSpan은 원하는 셀 수만큼 행을 병합할 수 있고 

layout_columnSpan은 원하는 셀 수만큼 열을 병합할 수 있다. 

특히 행 병합 속성인 layout_rowSpan은 TableLayout에서 

제공하지 않는 기능이며 GridLayout만의 장점이다. 

예제를 통해 layout_rowSpan 속성에 대해 이해해 보자. 


그림 16 GridLayout LayoutParams의 layout_rowSpan 속성  

 

예제에서 View2에 layout_rowSpan 속성값을 3이라고 주었다. 

이 의미는 View2가 위치한 셀을 포함해서 3개의 셀을 행 병합하라는 것이다. 

설정한 값대로 적용된 모습을 볼 수 있다. 

다음은 layout_column 속성에 대해서 살펴보자. 


그림 17 GridLayout LayoutParams의 layout_columnSpan 속성 

 

예제에서 View2에 layout_column 속성값을 3이라고 주었다. 

이 의미는 View2가 위치한 셀을 포함해서 3개의 셀을 열 병합하라는 것이다. 

설정한 값대로 적용된 모습을 볼 수 있다. 

 

 


 

■ GridLayout의 자식 뷰 맞춤형 자동 배치


자식 뷰들이 복잡하게 행/열 병합되어 있는 상황에서 새로운 뷰를 추가하는 경우 

어떤 방식으로 배치 되는지 확인해 볼 필요가 있다. 아래의 그림을 보자.

그림 18 자식 뷰의 자동 배치 구조 

<참고 - http://android-developers.blogspot.kr/2011/11/new-layout-widgets-space-and-gridlayout.html >

 

 

그림과 같이 뷰들이 복잡하게 존재하고 7번 자식 뷰를 추가한다면 어느 곳에 배치될까?

최종적으로 추가된 6번 자식 뷰를 기준으로 7번 뷰가 추가될 수 있는 적합한 공간을 탐색하여 추가되는 것을 볼 수 있다. 

이렇게 자식 뷰의 자동 배치 방식 알고리즘을 충분히 이해해야만 GridLayout을 좀더 쉽게 활용할 수 있다. 


위의 과정 직접 구현해 보기를 추천한다. 

분명 많은 시행 착오를 겪게 될 것이며 그 과정에서 GridLayout에 대해 많은 부분을 이해하게 된다. 

참고로 필자는 처음 GridLayout을 접하고 위의 내용을 테스트하기 위해 구현했을 때 꽤 많이 고생했던 기억이 난다.

리가 나쁜 필자는 총 1시간이상 매달려야만 했다. 여러분은 더욱 짧은 시간에 해 낼 수 있을 것이라 믿는다. 

아래의 예제는 꼭 스스로 구현해 본 후 확인용으로만 참조하도록 하자. 

 

그림 19 자식 뷰의 자동 배치 구현 

 

예상한 결과가 적용된 것을 볼 수 있다. 

 

 


 

■ GridLayout의 위한 도우미 뷰


GridLayout을 위한 Space 뷰라는 것이 존재한다. 이 뷰는 오로지 한가지 이유를 위해 만들어 졌다. 

어떤 상황에 필요한 뷰인지 그림을 통해 이해해 보자.

그림 20 Space 뷰의 필요성 

 

화면에 좌측에는 텍스트가 존재하고 우측에는 두 가지 버튼이 존재하는 레이아웃이다. 

GridLayout을 이용해서 구현이 가능할까? 

 

①,③은 이미 고정된 크기가 정해져 있고, 

②의 가변적인 빈 공간은 무엇으로 채워야만 한다. 

 

GridLayout의 특성상 각 셀을 채우기 위해서는 꼭 자식 뷰가 들어가야 하는 상황이다. 

이렇게 특정 빈 공간을 채우기 위해 바로 Space라는 뷰가 존재한다. 

잠시 Space 클래스에 대해서 살펴 보자. 

그림 21 Space 뷰 클래스 

 

뷰 클래스를 상속받은 Space 클래스는 뷰이다.

GridLayout과 같이 API 14부터 제공된다.


Space 뷰는 단지 뷰이다라는 것 이외에 특별한 기능이 전혀 없다. 

예를 들어 TextView는 화면에 텍스트를 표시하고 ImageView는 화면에 이미지를 

표시할 수 있지만 Space 뷰는 자신만의 기능이 존재하지 않는다. 

그렇다면 [그림 20]의 상황에서 어떻게 활용되는지 예제를 통해 이해해 보자.

그림 22 GridLayout을 위한 Space 뷰 활용

 

①,③번에서 텍스트와 버튼 뷰들이 자리를 잡고 있다. 

②의 Space 뷰는 오로지 텍스트와 버튼 뷰 사이에서 빈 공간을 차지하기 위해 사용되었다. 

Space 뷰는 하는 일이 거의 없기 때문에 성능과 메모리 측면에서 거의 영향을 주지 않는다. 

하지만 만일 Space 뷰가 존재하지 않았다면 GridLayout은 치명적인 문제점 한가지를 가지게 될 것이다. 

 

 


 

■ GridLayout의 장점과 단점


이미 GridLayout을 설명하면서 중간중간 장단점을 언급하였다. 

이 단원에서는 좀더 대표적인 장점과 단점 한가지씩을 말하고자 한다.

우선 GridLayout의 대표적인 장점을 예제를 통해 살펴보자.


그림 23 GridLaytout에 적합한 레이아웃 

 

간단한 텍스트(TextView)와 입력박스(EditText)로 구성된 레이아웃이다. 이 화면의 핵심은 아래와 같다. 

 두 행의 텍스트와 입력박스 간격이 서로 일치하는 것(테이블 형태)

 각 행의 텍스트 하단이 서로 수평으로 이루는 것(텍스트 기준라인 맞춤) 


GridLayout을 제외한 뷰그룹들을 상기하여 어떻게 화면을 구성해야 할지 생각해 보자. 

 

먼저 각 행의 텍스트를 기준라인에 맞추는 것은 LinearLayout, TableLayout, RelativeLayout 모두 가능하다. 

LinearLayout과 TableLayout은 자식 뷰를 수평으로 배치하면 자동으로 텍스트 기준라인에 맞춰주며

(기본으로 baselineAligned 속성이 true이다), RelativeLayout은 LayoutParams 속성인 layout_alignBaseline에 의해서 

텍스트를 기준라인에 맞출 수 있다. 문제는 두 행의 텍스트와 입력박스의 간격을 맞추는 것이다. 

RelativeLayout을 이용하면 구현은 가능하나 여러 자식 뷰들의 관계를 지정해야 하므로 복잡하며,

LinearLayout은 두 행의 테스트 너비를 동일하게 직접 입력해야 하는 부담감이 있다. 

TableLayout은 기본적으로 행과 열의 크기를 동일하게 맞추므로 가장 쉽게 구현할 수 있다. 

TableLayout을 이용하여 구현해 보자.


그림 24 GridLayout 장점 : TableLayout을 이용한 화면 구현  

 

실행화면을 보면 텍스트 기준라인을 맞췄고 두 행의 텍스트와 입력박스의 간격이 동일하다. 

레이아웃 자체가 2행2열의 테이블 구조이며 TableLayout은 최적의 판단임이 틀림없어 보인다.

하지만 TableLayout은 여러 개의 중첩된 뷰그룹을 사용하므로 1,2,3번과 같이 총 3개의 뷰그룹이 필요하다.

뷰그룹 개수가 늘어나면 그만큼 메모리 사용량이 증가하고 성능이 떨어진다. 


다음은 GridLayout을 이용하여 구현해 보자. 


그림 25 GridLayout 장점 : GridLayout을 이용한 화면 구현 

 

GridLayout 역시 아무런 설정을 하지 않아도 한 행의 텍스트 기준라인을 맞추며,

TableLayout과 유사하게 한 행의 모든 셀 높이와 한 열의 셀 너비를 동일하게 유지한다.

그러므로 그림과 같이 쉽게 레이아웃을 구성할 수 있었다. 

하지만 GridLayout은 중첩해서 뷰그룹을 사용할 필요가 없으므로 단 한 개의 뷰그룹만 이용하였다. 

즉 성능과 편의성 모두를 만족한 결과라고 할 수 있다. 


다음은 대표적인 단점을 예제를 통해 살펴보자.


그림 26 GridLayout으로 구현할 수 없는 레이아웃

 

본 레이아웃은 하나의 텍스트(TextView)와 버튼으로 구성되어 있다. 여기서 가장 핵심이 되는 사항은 아래와 같다. 

 구매버튼의 크기를 유지하고 좌측의 텍스트 영역은 남은 공간을 차지해야 한다.

 남은 공간은 다양한 화면 크기에 따라 가변적으로 변한다. (화면 가로 세로 전환)

 텍스트가 길어지면 자동으로 내려쓰기가 되어야 한다.


GridLayout을 제외한 다른 뷰그룹들을 상기하여 어떻게 화면을 구성해야 할지 생각해 보자.

LinearLayout과 RelativeLayout으로 모두 구현이 가능하다.

TableLayout은 무조건 두 개 이상의 뷰그룹을 중첩해서 사용하므로 제외한다.

둘 중 어느 것을 이용해도 상관 없으나 가장 간단하게 구현할 수 있는 LinearLayout으로 선택하자.

 

그림 27 GridLayout 단점 : LinearLayout을 이용한 화면 구현 

 

간단히 수평 배열 방식으로 두 가지 자식 뷰를 등록하고 버튼의 너비를 wrap_content 값으로 고정하였다. 

좌측 텍스트 부분은 남은 영역을 차지하도록 weight 속성을 이용하여 전체적인 레이아웃을 구현을 마친다. 

실행화면에서 가로/세로 전환은 에뮬레이터의 경우 Ctrl + F11 번을 누르면 전환된다. 

가로 모드에서는 텍스트 너비 공간이 부족하지 않아 한 줄로 표시되었고, 

세로 모드는 텍스트 영역이 좁아져 자동 내려쓰기가 되었다. 


다음은 GridLaytout을 이용하여 구현해 보자.

 

그림 28 GridLayout 단점 : GridLayout을 이용한 화면 구현

 

GridLayout은 수평 배열로 열수를 2개로 설정하였고, 텍스트와 버튼을 자식 뷰로 추가하였다. 

텍스트 영역은 버튼을 제외한 남은 공간을 차지해야 하므로 layout_gravity 속성값을 left | right 로 주었다.

( left | right 와 fill_horizontal 은 값은 의미이다). 가로모드인 경우 원하는 정상적인 결과이지만 세로모드의 

경우 텍스트가 한 줄로 표시되고 버튼을 밀어내고 있다. GridLayout은 이렇게 가변적 설정에 유연하지 못하다. 

뿐만 아니라 레이아웃을 구성할 때 가변적 너비 설정은 자주 사용되므로 치명적인 단점에 해당한다.

 

 


 

■ GridLayout 지원 라이브러리 사용


GridLayout은 API 14 부터 추가되었기 때문에 13 이하의 버전에서는 사용할 수 없다고 하였다.

구글에서는 이런 하위 호환성 문제를 해결하기 위해 상위 버전에서 추가된 중요한 기능들에 대해서

별도의 라이브러리를 제공하고 있다. 

GridLayout 역시도 별도의 라이브러리를 제공하며, 안드로이드 SDK를 설치할 때 같이 저장된다. 

직접 확인해 보도록 하자.

그림 29 라이브러리 존재 유무 확인하기

 

툴 바에서 Android SDK Manager 아이콘을 실행하자.

Android Support Library 가 바로 GridLayout 라이브러리를 포함하고 있다. 

만일 설치된 상태가 아니라면 Not installed라고 표시되고 설치되어 있다면 Installed라고 표시된다.
    만일 그림과 같이 Update available 이라고 표시된다면 설치는 되어 있으나 업데이트 할 항목이 존재한다는 의미다

GridLayout 라이브러리는 자신이 설치 시 설정한 안드로이드 SDK 폴더 내에 존재한다.

              AndroidSDK / extras / android / support / v7 / gridLayout

    직접 자신의 로컬 PC에서 확인해 보도록 하자.

만일 로컬 PC에 해당 라이브러리가 없다면 Install n Packages 버튼을 선택하여 내려받기를 시도하자.


GridLayout 라이브러리 명을 android-support-v7-gridlayout이라고 한다. 풀어서 설명하자면
안드로이드에서 지원하는 GridLayout 라이브러리이며, API 버전 7번부터 사용할 수 있다는 의미이다. 

android-support-v7-gridlayout 라이브러리를 사용해 보자.

 

그림 30 android-support-v7-gridlayout 라이브러리 추가하기


 

이클립스 메뉴에서 File을 선택하자.

라이브러리를 추가하기 위해 Import 메뉴를 선택하자.

android-support-v7-gridlayout 라이브러리를 작업공간으로 추가하기 위해
    Existing Android Code Into Workspace 항목을 선택한다.

Next 버튼을 선택하여 다음 과정을 진행한다.

 

그림 31 android-support-v7-gridlayout 라이브러리 폴더 선택하기

 

android-support-v7-gridlayout 라이브러리가 존재하는 폴더를 지정하기 위해 Browse... 버튼을 누른다.

안드로이드 SDK가 설치된 하위폴더에서 gridlayout 폴더를 선택한다.

확인 버튼을 눌러서 라이브러리 선택을 마친다.


그림 32 android-support-v7-gridlayout 추가 완료

 

자동으로 선택된 경로가 설정된다.

추가할 android-support-v7-gridlayout 라이브러리를 선택한다.

 

이클립스 작업공간으로 해당 라이브러리를 복사하기 위해 Copy projects into workspace 를 체크한다.
    만일 체크하지 않으면 자신의 작업 공간으로 복사하여 사용하지 않고 원본을 직접 사용하게 된다.
    실수로 원본을 잘못 수정할 수 있으므로 작업공간으로 복사하여 사용하는 것이 좋다.

Finish 버튼을 눌러 android-support-v7-gridlayout 라이브러리 추가를 마친다.

 

 

그림 33 android-support-v7-gridlayout 라이브러리 패키지 살펴보기

 

정상적으로 추가가 되었다면 패키지 탐색기 창에 android-support-v7-gridlayout 패키지가 등록되어 있을 것이다.

libs 폴더에 GridLayout 클래스들을 모아둔 라이브러리가 존재한다.

라이브러리 패키지에서 포함한 리소스 중 attrs.xml을 열어보자.

GridLayout에서 사용하는 속성과 GridLayout LayoutParams에서 사용하는 속성들이 정의 되어 있다.
    이는 레이아웃 XML에서 참조하기 위해 사용된다. 


android-support-v7-gridlayout 라이브러리 패키지에는 크게 중요한 두 가지 파일이 있다. 

첫 번째는 GridLayout 클래스들을 모아둔 라이브러리이고 두 번째는 attrs.xml 리소스이다.

GridLayout 라이브러리만 존재하면 될 것 같은데 attrs.xml 리소스가 필요할까?
attrs.xml 리소스는 XML 리소스에서 
GridLayout의 속성들을 정의하기 위해 꼭 필요하다. 

좀 더 상세한 내용은 직접 GridLayout 라이브러리를 사용할 때 설명하겠다.

GridLayout 라이브러리를 사용하기 위해 새로운 프로젝트를 생성하자.

그림 34 새로운 프로젝트 생성


필자는 위와 같은 설정으로 새로운 프로젝트를 생성하였다. 

꼭 같은 설정을 사용할 필요는 없다. 다만 각종 버전 정보는 GridLayout이 기본적으로 포함되지 않은 버전을 선택하도록 하자. 

GridLayout은 API 14부터 지원되므로 이전 버전을 선택하면 된다. 필자는 API 10을 선택하였다.

 

 

그림 35 새로 생성된 프로젝트에 android-support-v7-gridlayout 연결하기

 

정상적으로 새로운 프로젝트가 생성되었다면 패키지 탐색기 창에 프로젝트가 추가되었을 것이다.
    프로젝트 명에서 단축키 Alt + Enter를 실행하여 프로젝트 설정 창을 열자.
    (프로젝트 명에서 마우스 우측 버튼을 누르고 Properties 메뉴를 선택해도 된다).

안드로이드 라이브러리 관련 항목에서 add 버튼을 누르자.

이전에 추가한 android-support-v7-gridlayout 라이브러리 프로젝트를 선택하자.

확인 버튼을 눌러 라이브러리를 추가하자.


 

그림 36 android-support-v7-gridlayout 연결 완료

 

선택한 라이브러리가 추가되었다.

확인 버튼을 눌러 라이브러리 추가 설정을 마치도록 한다.


<잠깐만!!!>

 

안드로이드 라이브러리 프로젝트

 

일반적으로 안드로이드에서 라이브러리를 추가할 때 jar 형식의 라이브러리 파일을 사용하려는 패키지 libs 폴더에 복사한다. 그런데 GridLayout 라이브러리는 안드로이드 패키지 형식이며, 패키지 자체를 추가하는 방식이다. 
왜 그런 것일까? 바로 리소스 때문이다. GridLayout은 레이아웃 XML에서 사용될 수 있으며, 
대부분의 설정까지 가능하다.


 

 <GridLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:columnCount="2"

    android:orientation="horizontal" >

 

    <Button android:text="1" />

    <Button android:text="2" />

    <Button android:text="3" />

    <Button android:text="4" />

 

 </GridLayout>

 


이러한 GridLayout 항목 혹은 속성 값인 columnCount, orientation 등을 사용하기 위해서는 미리 정의된 스키마 리소스가 필요하다. 리소스는 R.java에 의해 자동으로 ID가 부여되고 이 값은 유일한 값이어야 하므로 미리 정의해서 사용될 수 없다.

 

그러므로 GridLayout 라이브러리에 GridLayout 리소스를 포함할 수 없어 두 가지를 묶어 패키지 형태로 제공되는 것이다. 이러한 형태를 안드로이드 라이브러리 패키지라고 부른다. 라이브러리에 리소스가 포함되는 경우는
꼭 안드로이드 라이브러리 패키지 형태로 만들어야 한다
.

 


 

그림 37 자동으로 생성된 GridLayout의 R.java

 

GridLayout 라이브러리를 추가하면 자동으로 GridLayout R.java가 생성된다. R.java를 열어보자.

GridLayout의 각종 속성 값들이 정의되어 있다.

 

이제 모든 준비가 끝났다.  GridLayout 라이브러리를 사용해 보도록 하자.


그림 38 XML 레이아웃에서 GridLayout 사용시 문제

 

기존에 사용하는 방식으로 간단한 XML 레이아웃을 구성하였다. 그림과 같은 실행결과를 예상하겠지만
컴파일에러로 실행조차 되지 않을 것이다. 그 이유는 바로 xmlns 설정에 있다.

xmlns:android 스키마에는 GridLayout에 대한 정보가 전혀 존재하지 않는다. 

그러므로 GridLayout과 관련된 항목이나 속성들이 정의되지 않아 에러가 발생된다.

아래와 같이 수정하도록 하자.


그림 39 레이아웃에서 GridLayout 사용시 문제

 

안드로이드 기본 뷰/뷰그룹이 아니라 직접 구현하거나 외부에서 라이브러리를 통해 구현된 경우는
    전체 패키지 명을 기입해야 한다. 안드로이드 기본 뷰/뷰그룹의 경우 이미 전체 패키지 명을 시스템이
    알고 있으므로 해당 뷰/뷰그룹명만 간략히 적어준다.

 

xmlns:gridlayout="http://schemas.android.com/apk/res-auto" 라고 GridLayout의 스키마 등록을 한다. 
    참고로 gridlayout은 필자가 임으로 정한 네임스페이스이다. 네임스페이스는 다른 스키마와 중복되지 않게
    원하는 이름으로 정의하면 된다. res-auto는 패키지 명을 적어주어야 하지만 GridLayout과 같이
    안드로이드 패키지 라이브러리를 사용할 때는 res-auto라고 적어준다.

2번에서 정의한 네임스페이스 명인 gridlayout을 참조해서 GridLayout의 속성을 정의한다.

2번에서 정의한 네임스페이스 명인 gridlayout을 참조해서 GridLayout LayoutParams 속성을 정의한다.


만일 앞으로 안드로이드에서 새로운 뷰/뷰그룹을 제공할 경우, GridLayout 라이브러리와 같은 방식으로 배포될 것이다.



● 어떤 뷰그룹이 효율적인가?


과연 여섯 가지 뷰그룹 중 어떤 것이 가장 효율적일까? 이는 사용 편의성과 성능,
그리고 다양한 해상도를 지원하는 유연성 이 세가지를 모두 만족해야 할 것이다.
아래의 표를 통해서 살펴보자.

 각 뷰그룹의 편의성, 성능, 유연성

뷰그룹 종류

편의성

성능

유연성

AbsoluteLayout

☆☆☆☆☆

개발자가 좌표 등의 정보를 직접 계산해야 하기 때문에 가장 불편하다.

★★★★★

개발자가 좌표 등을 직접 계산하여 입력하기 때문에 뷰그룹이 특별히 하는 일이 없어 성능이 가장 좋다.

☆☆☆☆☆

절대 좌표 기반이므로 유연할 수가 없다.

FrameLayout

평가 불가

FrameLayout은 단독으로 화면을 구성하기 어렵고, 다른 뷰그룹과 같이 사용된다.

GridLayout

★★☆☆☆

모든 뷰그룹의 장점을 모으려고 했으나  매우 난해하고 직관적이지 못하다.

★★★★☆

여러 개의 뷰그룹을 중첩해서 사용할 필요가 없으므로 성능은 좋다.

★★☆☆☆

유연한 하다고는 하나  어떻게 활용해야 할지 조차 알기 힘들고 어렵다.

LinearLayout

★★★★★

수직 혹은 수평 배치 구조이므로 뷰 배치 속성이 매우 적고 이해하기 쉽다.

★★☆☆☆

여러 개의 뷰그룹을 중첩으로 사용해야 하므로 성능은 좋지 않다.

★★★★☆

가중치에 따른 뷰 배치등과 같은 유연한 기능들을 제공한다.

TableLayout

★★☆☆☆

다양한 화면 구성에 사용될 수는 없고 테이블과 같은 특화된 레이아웃에 효율적이다.

★☆☆☆☆

행과 열을 표현하기 위해서 기본적으로 다수의 뷰그룹을 중첩해서 사용하므로 성능과 메모리 사용 측면에서 좋지 않다.

★★★☆☆

다양한 화면 구성에 사용될 수는 없고 테이블과 같은 특화된 레이아웃에 유연하다.

RelativeLayout

★★★☆☆

레이아웃을 구성하는 방법은 가장 직관적이나 설정해야 하는 속성의 개수가 너무 많아 다소 어렵다.

★★★★☆

여러 개의 뷰그룹을 중첩해서 사용하지 않아도 대부분의 레이아웃 구성이 가능하다.

★★★★☆

여러 뷰의 관계에 따를 배치 방식이므로 유연한 화면 구조를 가져갈 수 있다.


가장 효율적인 뷰그룹은 있을 수가 없다. 레이아웃 구성에 따라 적절히 섞어서 사용하는 것이 최선이다.
참고로 사용이 편리한 LinearLayout으로 전체적인 레이아웃의 분리하고 효율적인 RelativeLayout을 이용해서 분리된 구간 내에 각 뷰들의 상세히 배치를 하는 것이 가장 일반적이다. 또한 GridLayout과 TableLayout은
테이블 형태 뷰 배치에 적합하며, FrameLayout은 전체 화면을 차지하는 두 가지 레이아웃을 전환하여
보여 주어야 하는 경우 많이 사용된다.

 


<잠깐만!!!>

 

뷰그룹 성능에 대한 개발자의 강박관념

 

개발자들은 성능에 대해 매우 민감하다. 그러므로 지금까지 배운 뷰그룹 중 대부분의 개발자는 성능이 좋은
뷰그룹을 이용해여 화면을 구성해야 한다는 강박관념에 사로잡힐 것이다
. 

물론 필자  역시도 개발자 중 한 사람으로써 성능이 좋은 뷰 그룹을 이용해서 최적화된 화면을 구성하려고
노력하였다
. 물론 틀린 것은 아니다. 하지만 그 만큼 레이아웃 구성이 복잡해 지고 가독성이 떨어지는 단점이 있다. 개발에 있어서 가독성을 높히고 복잡도를 낮추는 것은 성능만큼이나 중요하게 여겨야 할 부분이다. 
가독성과 복잡도의 문제가 있는 결과물은 유지 보수 기간에 많은 시간을 낭비하게 된다(개발 기간보다
더 많은 시간을 낭비하거나 유지보수 자체가 힘들어지기도 한다
).

 

여기서 한가지 고민해 보자. 예를 들어 성능이 좋은 뷰그룹만을 이용한 레이아웃과 성능이 가장 떨어지는
뷰그룹을 이용한 레이아웃이 있을 때 각각 화면 구동 시간이 크게 차이가 있을까
?

필자
는 다양한 디바이스에서 어느 정도 복잡한 화면구성으로 테스트해 본 결과 그 차이는 10ms 정도의 차이 정도였다. 물론 더욱 복잡한 화면구성이나 성능이 떨어지는 단말기에서 10~100ms 정도의 차이가 더 날지도 모른다. 하지만 가독성과 복잡도를 포기하고 얻는 이점은 크지 않다고 볼 수 있다. 

그렇다면 성능이 떨어지는 뷰그룹을 맘껏 사용해도 될까? 
아래의 그림으로 그 해답을 찾아보자.

 

<그림>


 

①번의 경우 일반적인 레이아웃이다. 더욱 복잡해지더라도 이러한 구조는 성능에 큰 영향을 주지 않는다. 
문제는 ②의 리스트 레이아웃이다. 리스트의 경우 화면을 아래위로 빠르게 이동할 수 있다. 

그러므로 리스트의 각 항목들은 아주 빠르게 그려져야 하고, 레이아웃 구조에 따라 성능에 큰 영향을 준다. 
예를 들어 리스트 각 항목의 레이아웃을 성능에 최적화 하지 않은 경우 위아래로 리스트를 이동할 때
뚝뚝 끊어지면서 이동될 수 있다
. 하지만 걱정하지 말자. 리스트의 한 항목에 들어가는 레이아웃은 대부분
복잡할 이유가 없다
. 아래에서 리스트의 한 항목을 살펴보자.

 

<그림>


좌측에 이미지 하나와 우측에 텍스트가 전부이다. 어느 뷰그룹을 이용해도 간단히 구현할 수 있으므로
가장 성능이 좋은 레이아웃을 사용하면 된다
. 물론 더욱 복잡해 질 수도 있으나 리스트의 작은 영역에
들어갈 수 있는 뷰는 그리 많지 않을 것이다
. 좀더 상세한 내용은 리스트를 설명하는 장에서 진행한다.

 

정리하자면 일반적인 레이아웃 구성에서는 다양한 레이아웃을 적절히 이용하여 가독성을 높히고 복잡도를
낮추도록 노력하고
, 리스트와 같은 레이아웃 구성에서는 각 항목의 레이아웃을 최적화하도록 하자. 
참고로 가독성과 복잡도가 최적화 된 레이아웃이란 다른 개발자들이 쉽게 이해할 수 있는 레이아웃을 말한다.