안드로이드 테이블레이아웃. (Android TableLayout)

2017. 7. 28. 17:55


1. 안드로이드 TableLayout

지금까지 살펴 본 여러 Layout 클래스, 그 중에서 뷰의 화면 배치가 주 목적인 Layout 클래스를 사용하는 과정을 떠올려보면, 각 뷰(View)가 어디에 배치될 것인가에 대한 설정을, 개발자가 의도적으로 지정해야 하는 상황이 많습니다. 그런데 어떤 경우에는, 뷰(View)들 간의 위치 관계를 깊게 고민하지 않고 화면을 구성해도 되는 경우가 있습니다. 아래 그림과 같은 레이아웃을 구성한다고 가정해보죠.

TableLayout이 필요한 경우의 예


그림과 같은 구조를 만들기 위해 RelativeLayout을 사용한다면, 모든 자식(Children) 뷰에 상대적 위치 지정을 위한 속성을 일일이 지정해야 하므로, 레이아웃 작성이 번거로워질 수 있습니다. 그나마 LinearLayout을 사용하면 좀 더 편하게 만들 수 있지만, 자식(Children) 뷰들의 가중치(weight)를 하나하나 지정해줘야 하는 문제가 있습니다. 이보다 더 좋은 방법이 없을까요? 음.. 있습니다. 그것은 바로 TableLayout을 사용하는 것입니다.


TableLayout은 앞서 살펴 본 그림에서와 같이, 표 형태의 레이아웃을 만들 때 사용하는 Layout 클래스입니다. "Table"이라는 단어의 여러 의미 중에 "표"가 있다는 것을 떠올리면 TableLayout이 어떻게 표시되는지 쉽게 이해할 수 있습니다.


Table 단어의 의미


일반적으로 테이블(Table)은 가로 방향으로 나열되는 열(Column)과 세로 방향으로 나열되는 행(Row)으로 구성됩니다. 문서에서 표를 작성하는 과정을 떠올려보면 그 구조를 쉽게 이해할 수 있을텐데요. TableLayout에서도 비슷한 개념으로 자식(Children) 뷰 위젯들을 배치할 수 있습니다. 단, 하나의 행(Row)을 추가할 때는 "<TableRow>"라는 요소를 명시적으로 사용하지만, 열(Column)을 추가하는 요소는 별도로 정의되어 있지 않습니다. 대신, "<TableRow>"에 뷰(View) 위젯을 선언하는 것만으로 새로운 열(Column)이 추가됩니다.


그러므로 TableLayout에서는 하나의 뷰(View)가 하나의 셀(Cell)이 됩니다.


HTML 태그(Tag)를 다뤄본 개발자라면, <table> 태그를 통해 TableLayout의 동작 방식을 좀 더 쉽게 이해할 수 있습니다. 웹(Web) 문서 작성 중, 정적(static) 요소를 정의하기 위해 HTML 태그를 사용하는데, 이 중 표 모양의 문서를 만들 때 <table> 태그가 사용됩니다.


<table> 태그를 사용해 표를 만들 때는 반드시 하나 이상의 행(Row)이 추가되어야 하며, 이 때 <tr> 태그가 사용됩니다. 그리고 하나의 행(Row) 안에 하나의 열(Column)을 추가하려면 <td> 태그를 사용합니다. 만약 동일한 행(Row)에 또 다른 열을 추가하고자 한다면 <td>를 연속적으로 사용하면 됩니다. 물론, </td>라는 끝(End) 태그는 빠트리지 말아야겠죠.


즉, <table> 태그를 사용하여 표를 만든다면, <tr> 태그를 사용해 행(Row)을 하나 추가하고, 여러 <td> 태그를 연속으로 사용하여 열(Column)들을 추가합니다. 그리고 새로운 행(Row)을 추가하려면 새로운 <tr> 태그를 추가하고, 다시 <td>로 열을 추가하게 되는 것이죠.


TableLayout의 TableRow는 <table> 태그 아래의 <tr>과 같은 역할을 수행합니다. 하지만 <td> 역할을 수행하는 요소는 따로 존재하지 않습니다. 그냥 TableRow 밑에 자식(Children) 뷰 위젯을 추가는 것만으로 <td> 태그와 같은 결과를 낼 수 있습니다.

TableLayout과 <table>태그


2. TableLayout 사용법

2.1 TableLayout 기본 사용법

TableLayout을 사용하는 기본적인 방법은, TableLayout 아래에 TableRow를 선언하여 행(Row)을 추가하고, TableRow아래에 뷰(View) 위젯을 선언하여 열(Column)를 추가하는 것입니다.

TableLayout 기본 사용법 : TableLayout에 TableRow와 뷰(View) 위젯 추가.
    <TableLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TableRow>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="24sp"
                android:background="#F44336"
                android:textColor="#FFFFFF"
                android:text="A" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="24sp"
                android:background="#9C27B0"
                android:textColor="#FFFFFF"
                android:text="B" />
        </TableRow>
        <TableRow>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="24sp"
                android:background="#3F51B5"
                android:textColor="#FFFFFF"
                android:text="1" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="24sp"
                android:background="#00BCD4"
                android:textColor="#000000"
                android:text="2" />
        </TableRow>
    </TableLayout>

TableLayout 기본 사용법


2.2 TableLayout 열(Column)의 갯수(count)

TableLayout 열(Column)의 갯수는 가장 많은 셀(Cell)을 가진 TableRow의 셀(Cell)의 갯수에 맞춰집니다. 예를 들어, 세 개의 TableRow가 각각 4, 2, 1개의 셀(Cell)을 가지는 경우, TableLayout의 전체 열(Column) 갯수는 4개가 됩니다. 이 때, TableLayout 열(Column)의 갯수보다 적은 수의 셀(Cell)을 가진 TableRow는 모자란 셀(Cell) 영역을 빈 공간으로 남겨두게 됩니다.

TableLayout의 최대 열(Column)의 갯수 : 가장 많은 자식(Chilren)을 가진 TableRow에 맞춰짐.
    <TableLayout ...>
        <TableRow ...>
            <TextView ...  androidid:text="A" />
            <TextView ...  androidid:text="B" />
            <TextView ...  androidid:text="C" />
            <TextView ...  androidid:text="D" />
        </TableRow>
        <TableRow ...>
            <TextView ...  androidid:text="1" />
            <TextView ...  androidid:text="2" />
        </TableRow>
        <TableRow ...>
            <TextView ...  androidid:text="a" />
        </TableRow>
    </TableLayout>

tablelayout_column_count


2.3 TableLayout 열(Column)의 너비(width)

기본적으로 TableLayout 열(Column)의 너비는 다른 행(Row), 같은 열(Column)의 셀(Cell) 중에서 가장 넓은 열(Column)의 너비에 맞춰집니다. 즉, TableLayout의 여러 TableRow에 추가된 같은 열(Column)의 자식(Children) 뷰 위젯 중에서, 가장 큰 너비를 가진 뷰(View) 위젯의 너비에 맞춰진다는 것입니다.

TableLayout 열(Column)의 너비 : 가장 넓은 열(Column)의 너비에 맞춰짐.
    <TableLayout ...>
        <TableRow>
            <TextView ...  android:text="AAAAAAAAAA" />
            <TextView ...  android:text="B" />
        </TableRow>
        <TableRow>
            <TextView ...  android:text="1" />
            <TextView ...  android:text="2" />
        </TableRow>
    </TableLayout>

TableLayout 열의 너비


예제 코드의 실행 화면을 보면, 첫 번째 열(Column)의 너비가 첫 번째 셀(Cell)인 "AAAAAAAAAA"의 크기와 정확히 일치하는 것을 확인할 수 있습니다.


그런데 예제 화면에서, TableLayout의 내용이 한쪽으로 치우쳐진 것을 볼 수 있습니다. 이는 모든 셀이 기본적으로 자신의 내용에 맞춰진 너비로 지정되기 때문입니다. 하지만 TableLayout을 사용하고자 하는 대부분의 경우, 이렇게 한쪽으로 쏠린 형태로 표시되길 원하는 경우는 거의 없을 것입니다. 대신 TableLayout의 전체 너비를 균등 분할(1/N)한 크기로 열(Column)의 너비를 지정하거나, 열(Column)의 위치(index)에 따라 어떤 열(Column)은 내용의 크기대로 표시하고, 다른 열은 나머지 공간을 모두 차지하도록 늘려서(stretch) 표시하고자 하는 경우가 더 많겠죠.


자 그럼, 어떻게 하면 TableLayout의 전체 너비를 고르게 사용할 수 있도록 만들 수 있을까요? 바로, TableLayout의 stretchColumns 속성을 사용하는 것입니다. stretchColumns 속성은, "stretch(늘이다)"와 "Columns(열)"라는 단어의 의미대로, TableLayout의 열 중에서 그 너비를 늘여서(stretch) 표시할 열(Column)을 지정하는 속성입니다.

  * android:stretchColumns - 늘이고자 하는 열(Column)의 인덱스 지정.
        > 열(Column)의 인덱스는 0부터 시작. (zero-based)
        > 하나 이상의 열(Column)을 ','(comma)로 분리하여 지정. (예. "0,2,4")
        > 모든 열(Column)을 지정하려면, '*'기호 사용.

아래와 같은 구조를 예를 들어 stretchColumns 속성의 동작을 알아보도록 하겠습니다.

    <TableLayout ...>
        <TableRow>
            <TextView ...  android:text="A" />
            <TextView ...  android:text="B" />
            <TextView ...  android:text="C" />
            <TextView ...  android:text="D" />
        </TableRow>
        <TableRow>
            <TextView ...  android:text="1" />
            <TextView ...  android:text="2" />
            <TextView ...  android:text="3" />
            <TextView ...  android:text="4" />
        </TableRow>
    </TableLayout>

TableLayout stretchColumns 예제 1


예제의 TableLayout은 전체 4개의 열(Column)로 구성되어 있는데요, 만약 첫 번째와 세 번째는 원래 크기대로 표시하고, 두 번째와 네 번째 열만 너비를 늘이고자 한다면, stretchColumns에 "1,3"을 지정하면 됩니다. (첫 번째 열이 0부터(zero-based) 시작한다는 것에 주의하세요.)

TableLayout의 stretchColumns 속성 : 지정된 열 너비 늘이기.
    <TableLayout ...
        android:stretchColumns="1,3">
        <TableRow>
            <TextView ...  android:text="A" />
            <TextView ...  android:text="B" />
            <TextView ...  android:text="C" />
            <TextView ...  android:text="D" />
        </TableRow>
        <TableRow>
            <TextView ...  android:text="1" />
            <TextView ...  android:text="2" />
            <TextView ...  android:text="3" />
            <TextView ...  android:text="4" />
        </TableRow>
    </TableLayout>

TableLayout stretchColumns 예제 2


만약, 전체 열(Column)의 너비가 늘어나게 만드려면, stretchColumns에 "*" 값을 지정하면 됩니다.

TableLayout의 stretchColumns 속성 : 모든 열 너비 늘이기.
    <TableLayout ...
        android:stretchColumns="*">
        <TableRow>
            <TextView ...  android:text="A" />
            <TextView ...  android:text="B" />
            <TextView ...  android:text="C" />
            <TextView ...  android:text="D" />
        </TableRow>
        <TableRow>
            <TextView ...  android:text="1" />
            <TextView ...  android:text="2" />
            <TextView ...  android:text="3" />
            <TextView ...  android:text="4" />
        </TableRow>
    </TableLayout>

TableLayout stretchColumns 예제 3


2.4 TableLayout 행(Row)의 높이(height)

TableLayout 행(Row)의 높이도 열(Column)의 너비와 마찬가지로, 한 행(Row)의 셀(Cell) 중에서 가장 높은 셀(Cell)의 높이에 맞춰집니다.

TableLayout 행(Row)의 높이 : 가장 높은 셀(Cell)의 높이에 맞춰짐.
    <TableLayout ...
        android:stretchColumns="*">
        <TableRow>
            <TextView ...
                android:layout_height="match_parent"
                android:textSize="48sp"
                android:text="A" />
            <TextView ...
                android:layout_height="match_parent"
                android:text="B" />
            <TextView ...
                android:layout_height="match_parent"
                android:text="B" />
            <TextView ...
                android:layout_height="match_parent"
                android:text="B" />
        </TableRow>
        <TableRow>
            <TextView ...
                android:layout_height="match_parent"
                android:text="1" />
            <TextView ...
                android:layout_height="match_parent"
                android:text="2" />
            <TextView ...
                android:layout_height="match_parent"
                android:text="3" />
            <TextView ...
                android:layout_height="match_parent"
                android:textSize="60sp"
                android:text="4" />
        </TableRow>
    </TableLayout>

TableLayout 행의 높이


참고로, 행(Row) 높이와 관련하여, 열(Column)에서 사용했던 stretchColumns와 같은 속성은 존재하지 않습니다.

2.5 TableLayout, 개별 행(Row), 개별 셀(Cell)의 배경색 지정.

전체 TableLayout의 배경 색상을 변경하려면 "<TableLayout>" 요소에 "background" 속성을 사용하면 됩니다. 그리고 개별 행(Row) 전체의 배경 색상을 변경하려면 "<TableRow>"에 "background" 속성을 사용합니다. 마지막으로 하나의 셀(Cell) 영역의 배경 색상만을 변경하고자 한다면, 셀(Cell)에 해당하는 뷰(View) 위젯의 배경을 직접 변경하면 됩니다.


아래 예제는 TableLayout, TableRow, 그리고 뷰(View) 위젯에 bacground 속성을 사용하여 배경을 지정한 예제입니다.

TableLayout 또는 개별 행(Row)의 배경색 지정.
    <TableLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:background="#FF0000"
        android:padding="8dp"
        android:stretchColumns="*">

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#00FF00"
            android:padding="8dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="4dp"
                android:gravity="center"
                android:textSize="24sp"
                android:textColor="#FFFFFF"
                android:background="#3F51B5"
                android:text="A" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="24sp"
                android:textColor="#FFFFFF"
                android:background="#9C27B0"
                android:text="B" />
        </TableRow>
    </TableLayout>

TableLayout 요소의 배경색 지정


TableLayout, TableRow의 배경색과 padding, layout_margin 속성을 이용하여 TableLayout에 테두리가 그려진 효과를 낼 수 있습니다.

TableLayout에 테두리 그리기
    <TableLayout
        android:background="#FF0000"
        android:padding="8dp"
        android:stretchColumns="*">

        <TableRow
            android:background="#000000">
            <TextView ... android:layout_margin="1dp"/>
            <TextView ... android:layout_margin="1dp"/>
            ...
        </TableRow>
        <TableRow
            android:background="#000000">
            <TextView ... android:layout_margin="1dp"/>
            <TextView ... android:layout_margin="1dp"/>
            ...
        </TableRow>
        ...
    </TableLayout>

TableLayout에 테두리 그리기


3. TableLayout의 속성과 TableLayout.LayoutParams.

앞서 살펴본 기본 사용법에 더하여, TableLayout에는 다양한 방법과 형태의 레이아웃 구성을 위한 속성 및 LayoutParams가 제공됩니다. 지금부터 TableLayout 속성과 LayoutParams에 대해 살펴보도록 하겠습니다.

3.1 열(Column) 번호를 지정하여 셀(Cell) 추가하기. (layout_column)

아무런 옵션 없이 TableLayout의 행(Row)에 셀(Cell)을 추가하면, 자동적으로 열(Column) 번호가 증가합니다. 최초 추가되는 열(Column) 번호는 0부터 시작하며, 그 다음에 추가되는 셀(Cell)은 열(Column) 번호가 하나씩 증가하는 것이죠. 그런데 TableRow의 LayoutParams에는 순차적으로 셀(Cell)을 추가하지 않고, 열(Column)의 순서를 직접 지정하여 원하는 열(Column)에 바로 셀(Cell)을 추가하는 속성이 있습니다. layout_column이라는 속성입니다.

  * android:layout_column - 뷰(View)가 추가될 열(Column) 인덱스 지정.
        > 정수 값 사용. (예. 3)
TableRow.LayoutParams layout_column 속성 : 지정한 열(Column)에 셀(Cell) 추가하기.
    <TableLayout ...
        android:stretchColumns="*">

        <TableRow>
            <TextView ...
                android:text="A" />
            <TextView ...
                android:text="B" />
        </TableRow>

        <TableRow>
            <TextView ...
                android:text="1" />
            <TextView ...
                android:text="2"
                android:layout_column="4" />
        </TableRow>
    </TableLayout>

TableLayout layout_column 속성


예제 코드의 실행 화면을 보면, 두 번째 행(Row), 두 번째 셀(Cell)의 layout_column 속성에 "4"를 지정하여, 1~3번 열(Column)을 건너뛰고 4번 열(Column)에 셀(Cell)이 바로 추가된 것을 확인할 수 있습니다.

3.2 두 개 이상의 셀(Cell) 합치기. (layout_span)

앞서 HTML "<table>" 태그와 TableLayout의 유사성에 대해 언급하였습니다. 요소의 이름과 사용법에는 다소 차이가 있지만, 테이블을 구성하는 기본 절차는 유사하죠. 그리고 또 하나의 유사성이 있습니다. 바로 셀(Cell) 합치기 기능이죠.


HTML의 "<td>" 태그에는 두 개 이상의 셀(Cell)을 합치는데 사용되는 colspan과 rowspan 속성이 존재합니다. colspan은 열(Column) 방향으로 셀(Cell)을 합치는 속성이고, rowspan은 행(Row) 방향으로 두 개 이상의 셀(Cell)을 합치는 속성입니다.


그리고 안드로이드의 TableLayout에도 셀(Cell)을 합치는데 사용되는 속성이 있습니다. 바로 layout_span 속성입니다.

  * android:layout_span - 합치고자 하는 셀(Cell)의 개수 지정.
        > 정수 값 사용. (예. 3)
        > 열(Column) 방향으로만 셀(Cell) 합치기 가능.
        > 값이 지정된 셀(Cell)의 오른쪽 방향으로 셀(Cell)이 합쳐짐.
        > 1이상의 값 사용 가능.

layout_span 속성을 사용하여 두 개 이상의 셀(Cell)을 합치는 예제는 아래와 같습니다.

TableRow.LayoutParams layout_span 속성 : 두 개 이상의 셀(Cell) 합치기.
    <TableLayout ...
        android:stretchColumns="*">

        <TableRow>
            <TextView ...
                android:text="A" />
            <TextView ...
                android:text="B" />
            <TextView ...
                android:text="C" />
        </TableRow>

        <TableRow>
            <TextView ...
                android:text="1" />
            <TextView ...
                android:text="2"
                android:layout_span="2" />
        </TableRow>
    </TableLayout>

TableLayout layout_span 속성


layout_span을 사용함에 있어 주의할 점은, layout_span이 열(Column) 방향으로의 셀(Cell) 합치기만 지원한다는 것입니다. TableLayout에는 두 개의 행(Row)에 걸쳐 셀(Cell)을 합치는 기능은 제공되지 않습니다.

3.3 셀(Cell) 감추기. (collapseColumns)

TableLayout을 사용하다보면, 필요에 따라 특정 열(Column)을 감춰야 하는 경우가 있습니다. 표시해야 할 정보의 종류가 늘어나 열의 개수가 많아지면, 중요도가 낮은 정보를 가진 열(Column)은 보이지 않게 만듦으로써 내용을 좀 더 간결하게 표시할 수 있는 것이죠. 이 때, 특정 열(Column)을 보이지 않게 만드는 속성을 사용하면 되는데, 바로 collapseColumns 속성입니다.

  * android:collapseColumns - 감추고자 하는 열(Column)의 인덱스 지정.
        > 열(Column)의 인덱스는 0부터 시작. (zero-based)
        > 하나 이상의 열(Column)을 ','(comma)로 분리하여 지정. (예. "0,2,4")
        > 모든 열(Column)을 지정하려면, '*'기호 사용.

아래 예제는 TableLayout에 collapseColumns 속성을 사용하여, 1번과 2번 열(Column)을 보이지 않도록 만든 코드입니다.

TableLayout collapseColumns 속성 : 지정한 열(Column) 감추기.
    <TableLayout ...
        android:stretchColumns="*"
        android:collapseColumns="1,2">

        <TableRow>
            <TextView ...  android:text="A" />
            <TextView ...  android:text="B" />
            <TextView ...  android:text="C" />
            <TextView ...  android:text="D" />
            <TextView ...  android:text="E" />
        </TableRow>

        <TableRow>
            <TextView ...  android:text="1" />
            <TextView ...  android:text="2" />
            <TextView ...  android:text="3" />
            <TextView ...  android:text="4" />
            <TextView ...  android:text="5" />
        </TableRow>
    </TableLayout>

TableLayout collapseColumns 속성


3.4 열(Column) 너비(width)가 자동으로 줄어들게 만들기. (shrinkColumns)

일반적인 경우, TableLayout 열(Column)의 너비에 대한 고민은, "어떻게 늘일 수 있는가"에 맞춰집니다. 열(Column)의 너비가 셀(Cell)의 내용에 맞춰지게 되면, 모든 내용이 한쪽으로 쏠리게 되기 때문에, 어떤 셀(Cell)들은 그 너비를 적당히 늘려서 표시할 필요가 있는 것이죠. 이를 위해 stretchColumns 라는 속성을 사용하는 방법에 대해 알아보았습니다.


그런데 반대의 경우를 생각해보죠. 만약 셀(Cell)의 너비가 점점 커져서 TableLayout의 전체 너비를 넘어버리게 되면, 오른쪽 열(Column)의 내용이 화면에 표시되지 않는 문제가 발생하게 됩니다. 아래의 경우처럼 말이죠.

    <TableLayout ...
        android:stretchColumns="*">

        <TableRow>
            <TextView ...  android:text="AAAAAAAAAA" />
            <TextView ...  android:text="BBBBBBBBBB" />
            <TextView ...  android:text="CCCCCCCCCC" />
            <TextView ...  android:text="DDDDDDDDDD" />
            <TextView ...  android:text="EEEEEEEEEE" />
        </TableRow>

        <TableRow>
            <TextView ...  android:text="1111111111" />
            <TextView ...  android:text="2222222222" />
            <TextView ...  android:text="3333333333" />
            <TextView ...  android:text="4444444444" />
            <TextView ...  android:text="5555555555" />
        </TableRow>
    </TableLayout>

TableLayout shrinkColumns 속성 1


자, 이렇게 TableLayout의 내용이 전체 너비를 넘어버리는 경우 우리가 선택할 수 있는 가장 직관적인 방법은, 특정 열(Column)의 너비를 자동으로 줄여서 TableLayout 전체 너비를 넘어서지 않도록 만드는 것입니다. 이 때 사용하는 속성이 바로 shrinkColumns 입니다.

  * android:shrinkColumns - 줄이고자 하는 열(Column)의 인덱스 지정.
        > 열(Column)의 인덱스는 0부터 시작. (zero-based)
        > 하나 이상의 열(Column)을 ','(comma)로 분리하여 지정. (예. "0,2,4")
        > 모든 열(Column)을 지정하려면, '*'기호 사용.

아래 예제는 shrinkColumns 속성에 "*"를 지정하여, 모든 열을 TableLayout의 너비에 맞게 줄인 결과를 보여줍니다.

TableLayout shrinkColumns 속성 : 지정한 열(Column)의 너비 줄이기.
    <TableLayout ...
        android:stretchColumns="*"
        android:shrinkColumns="*">

        <TableRow>
            <TextView ...  android:text="AAAAAAAAAA" />
            <TextView ...  android:text="BBBBBBBBBB" />
            <TextView ...  android:text="CCCCCCCCCC" />
            <TextView ...  android:text="DDDDDDDDDD" />
            <TextView ...  android:text="EEEEEEEEEE" />
        </TableRow>

        <TableRow>
            <TextView ...  android:text="1111111111" />
            <TextView ...  android:text="2222222222" />
            <TextView ...  android:text="3333333333" />
            <TextView ...  android:text="4444444444" />
            <TextView ...  android:text="5555555555" />
        </TableRow>
    </TableLayout>

TableLayout shrinkColumns 속성 2


4. TableLayout과 TableRow, 그리고 LinearLayout.

TableLayout의 동작과 화면 표시 형태가, 앞서 다른 글에서 살펴본 여러 레이아웃들과는 전혀 다른 새로운 형태의 레이아웃으로 여겨질 수도 있지만, 가만히 살펴보면 LinearLayout과 유사한 특징이 있음을 눈치챌 수 있습니다. 바로, 가로와 세로 방향으로 자식(Children) 뷰 위젯을 정렬한다는 것이죠.


LinearLayout은 orientation 속성에 따라, 가로 또는 세로 방향으로 자식(Children) 뷰 위젯을 정렬할 때 사용하는 레이아웃입니다. 그리고 TableLayout은 가로와 세로, 두 가지 방향으로 자식(Children) 뷰 위젯을 정렬하는 레이아웃이죠. 특히 TableRowTableLayout의 자식(Children)으로 사용된다는 것을 생각하면, TableLayout은 orientation이 vertical인 LinearLayout과 그 동작이 매우 유사하다고 할 수 있습니다.


그렇다면, 안드로이드에서는 이러한 유사점을 무시한 채, LinearLayoutTableLayout을 전혀 상관없는 클래스로 디자인했을까요? 아니오. 그렇지 않습니다. 좀 더 확장된 형태로 동작하는 TableLayoutLinearLayout을 상속받도록 설계하였습니다. 즉, LinearLayoutTableLayout의 부모인 것입니다.

TableLayout 클래스 상속 계층도


TableRow도 마찬가지입니다. TableLayout에 하나의 행을 추가할 때 사용하는 TableRow는 orientaion이 horizontal인 LinearLayout과 동일한 방식으로 동작하죠. 그래서 TableRowLinearLayout을 상속합니다.

TableRow 클래스 상속 계층도


자, 그렇다면 TableLayoutTableRowLinearLayout을 상속받았다는 것이 무엇을 의미할까요? 바로, LinearLayout에 구현된 기능들을 사용할 수 있다는 것이죠. 어떤 기능들이 사용될 수 있는지는 지금부터 여러 예제들을 통해 살펴보도록 하겠습니다.

4.1 layout_weight를 사용하여 TableRow의 셀(Cell) 너비 조절하기.

[안드로이드 레이아웃 (Android Layout) - 3. 가중치(weight)를 이용한 영역 분할]에서 확인할 수 있듯이, LinearLayout에는 가중치(weight)를 이용하여, 지정된 비율에 따라 레이아웃의 영역을 분할하는 기능이 제공됩니다. layout_weight라는 속성으로 말이죠.


마찬가지로, LinearLayout을 상속받은 TableLayout에서도 layout_weight 속성을 사용하여 자식(Children)들의 영역을 비율에 따라 분할할 수 있습니다. 그리고 다시 한번 강조하자만, layout_weight 속성을 사용할 때는 layout_width 속성 값이 "0dp"로 지정되어야 정확히 의도하는 결과가 표시됩니다.

layout_weight 속성으로 열(Column) 너비 조절하기.
    <TableLayout ...>

        <TableRow>
            <TextView ...
                android:layout_width="0dp"
                android:layout_weight="1"
                android:text="A" />
            <TextView ...
                android:layout_width="0dp"
                android:layout_weight="2"
                android:text="B" />
            <TextView ...
                android:layout_width="0dp"
                android:layout_weight="3"
                android:text="C" />
        </TableRow>

        <TableRow>
            <TextView ...
                android:text="1" />
            <TextView ...
                android:text="2" />
            <TextView ...
                android:text="3" />
        </TableRow>
    </TableLayout>

TableLayout에서 layout_weight로 셀 너비 조절하기


단, layout_weight에 의한 열(Column) 너비 조절은 해당 TableRow에만 적용됩니다. 앞서 "2.3 TableLayout 열(Column)의 너비(width)"에서 설명했던, TableLayout의 전체 열(Column) 너비 결정 과정에 layout_weight에 의해 조절된 너비는 포함되지 않는 것이죠. 예제 화면의 두 번째 TableRow를 보면 그 의미를 확인할 수 있습니다.


그리고 layout_weight에 의해 조절된 열(Column)의 너비는 stretchColumns나 shrinkColumns 속성에도 영향을 받지 않습니다. 그러므로 layout_weight를 사용하여 모든 행(Row)이 같은 너비의 열을 갖도록 만드려면, 모든 셀(Cell)에 layout_weight 속성 값을 지정해야 합니다.

4.2 layout_weight를 사용하여 TableLayout의 TableRow 높이 조절하기.

TableLayout의 열(Column)들이 전체 영역을 고르게 사용할 수 있게 만드는 방법은, stretchColumns 속성을 사용하여 특정 열(Column) 또는 모든 열(Column)이 전체 너비에 맞게 늘어나게 만드는 것입니다. 그런데 행(Row)의 높이가 전체 영역에 맞게 늘어나게 만드려면 어떻게 해야 할까요? 단어 의미대로라면 stretchRows라는 속성이 있을 것 같은데, 그런 이름의 속성은 존재하지 않죠. 아니, 애초에 행(Row)의 높이를 전체 영역에 맞게 늘어나도록 만드는 속성은 존재하지 않습니다. 그럼 전혀 방법이 없는 걸까요?


이 때, TableLayoutLinearLayout의 자식이라는 것을 떠올려보면, 그 방법을 쉽게 유추해낼 수 있습니다. 바로, layout_weight 속성을 사용하는 것이죠. 물론, TableLayout의 layout_height는 "0dp"로 지정되어야 하며, layout_weight 속성은 TableLayout의 자식(Children)으로 사용되는 TableRow에 사용되어야 합니다.

layout_weight 속성으로 행(Row) 높이 조절하기.
    <TableLayout ...
        android:stretchColumns="*">

        <TableRow
            android:layout_height="0dp"
            android:layout_weight="1">

            <TextView ...  android:text="A" />
            <TextView ...  android:text="B" />
            <TextView ...  android:text="C" />
        </TableRow>

        <TableRow
            android:layout_height="0dp"
            android:layout_weight="1">

            <TextView ...  android:text="1" />
            <TextView ...  android:text="2" />
            <TextView ...  android:text="3" />
        </TableRow>

    </TableLayout>

TableLayout에서 layout_weight로 TableRow 높이 조절하기


4.3 TableRow가 아닌 뷰 위젯을 TableLayout의 자식으로 추가하기.

TableLayout에 하나의 행(Row)을 추가하기 위해서 TableRow를 사용하는게 일반적이지만, 다른 뷰(View) 위젯을 사용하여 TableLayout의 행(Row)을 추가할 수도 있습니다.

TableLayout의 행으로 TableRow가 아닌 일반 뷰(View) 사용하기.
    <TableLayout ...
        android:stretchColumns="*">

        <TableRow>
            <TextView ...  android:text="A" />
            <TextView ...  android:text="B" />
            <TextView ...  android:text="C" />
        </TableRow>

        <TextView ...
            android:text="TextView as Row">

        <TableRow>
            <TextView ...  android:text="1" />
            <TextView ...  android:text="2" />
            <TextView ...  android:text="3" />
        </TableRow>

    </TableLayout>

TableRow가 아닌 뷰 위젯을 TableLayout의 자식으로 추가하기


5. TableLayout 사용 예제

5.1 균등한 화면 분할이 필요한 화면. (계산기)

아마도 TableLayout을 사용하는 대부분의 경우는, 전체 영역을 동일한 비율로 나눈, 같은 크기의 셀(Cell)들로 레이아웃을 구성하려는 경우일 것입니다. 계산기 화면이 그 예가 될 수 있겠죠.

    <TableLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="8dp"
        android:background="#404040"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:stretchColumns="*">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="4"
            android:textSize="60sp"
            android:textColor="#FFFFFF"
            android:background="#607D8B"
            android:gravity="right|center_vertical"
            android:text="0" />

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="1">

            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="7" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="8" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="9" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_span="2"
                android:textSize="32sp"
                android:text="DEL" />

        </TableRow>

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="1">

            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="4" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="5" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="6" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="+" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="-" />
        </TableRow>

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="1">

            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="1" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="2" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="3" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="*" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="/" />

        </TableRow>

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="1">

            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_span="2"
                android:textSize="32sp"
                android:text="0" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="32sp"
                android:text="." />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_span="2"
                android:textSize="32sp"
                android:text="=" />

        </TableRow>
    </TableLayout>

TableLayout으로 계산기 만들기


5.2 표 형태의 화면.

TableLayout 사용의 또 다른 예로, 아래와 같은 표 형태의 레이아웃을 들 수 있습니다.

    <TableLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:stretchColumns="*"
        android:shrinkColumns="*">

        <TableRow>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_span="7"
                android:background="#00BCD4"
                android:gravity="center"
                android:textSize="32sp"
                android:text="TITLE" />

        </TableRow>

        <TableRow>

            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="16sp"
                android:text="1" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="16sp"
                android:text="2" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="16sp"
                android:text="3" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="16sp"
                android:text="4" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="16sp"
                android:text="5" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="16sp"
                android:text="6" />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="16sp"
                android:text="7" />

        </TableRow>

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <ImageView
                android:layout_width="300dp"
                android:layout_height="150dp"
                android:background="#FFC107"
                android:id="@+id/image1" />

            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/text2"
                android:layout_toRightOf="@id/image1"
                android:text="INSERT" />

            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/text3"
                android:layout_below="@id/text2"
                android:layout_alignLeft="@id/text2"
                android:text="MODIFY" />

            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/text4"
                android:layout_below="@id/text3"
                android:layout_alignLeft="@id/text2"
                android:text="DELETE" />
        </RelativeLayout>

        <TableRow
            android:layout_marginTop="4dp">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_span="2"
                android:background="#8BC34A"
                android:textSize="24sp"
                android:gravity="center"
                android:text="ITEM-1" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_span="5"
                android:background="#CDDC39"
                android:textSize="24sp"
                android:gravity="center"
                android:text="DESC-1" />
        </TableRow>

        <TableRow
            android:layout_marginTop="4dp">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_span="2"
                android:background="#8BC34A"
                android:textSize="24sp"
                android:gravity="center"
                android:text="ITEM-2" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_span="5"
                android:background="#CDDC39"
                android:textSize="24sp"
                android:gravity="center"
                android:text="DESC-2" />
        </TableRow>
    </TableLayout>

TableLayout으로 표 만들기


6. 참고.

.END.


ANDROID 프로그래밍/LAYOUT , , , , , , , , , , , , , , , , , ,

  1. Blog Icon
    내멋으로

    자주 들어와보고 있습니다.
    볼때마다 깊이 감사 하고 있습니다.

    이런 훌륭한 내용을 공개해주신분을 보면 정말 대단하시다는 감탄만 나올 뿐입니다.

    더운 여름 건강 잘 챙기십시요

  2. 저에게 과분한 칭찬을 해주셨군요.
    가끔 제가 쓴 글을 다시 읽어보곤 하는데...
    부끄럽고, 또 참으로 모자라단 생각이 드네요.

    그래도 이런 격려 댓글 덕분에 좀 더 잘 쓰고 싶다는 욕심이 생기기도 합니다.

    "내멋으로" 님도 더위 잘 이겨 내세요.
    좋은 말씀 감사합니다.

  3. 정말 잘보고 있어요~

  4. 아직 내용이 부족하고, 미흡하네요.
    좀 더 다양한 내용들 담을 수 있도록 노력하겠습니다.

    감사합니다.

  5. Blog Icon
    moon

    정보통신과 학생입니다.
    java를 배우고 안드로이드 수업을 받는중인데 정말 많은 도움이 되고있어요.
    감사합니다.

  6. 볼 것 없는 블로그가 도움이 된다니 다행입니다.
    방문해 주셔서, 저야말로 감사드립니다.

  7. Blog Icon
    나그네

    와우~ 한번에 케이스별로 잘 정리 해주셔서 너무 좋아요.
    댓글을 안쓸수가 없네요. 감사합니다.~

  8. 작성한 내용이 도움을 드린 것 같아서 뿌듯하네요.
    방문해 주셔서 감사합니다. ^^

  9. Blog Icon
    GODISGOOD

    ㅠㅠ 진짜 정말 이렇게 올리시는거 대단하신것 같습니다..ㅠㅠ
    질문이 있는데 테이블 테두리 그리는 게ㅠㅠㅠ 저 화면처럼 나오질 않습니다..ㅠㅠ 맞게 따라 쳣는데요..ㅠㅠ

  10. 일단 본문의 예제 코드와 이미지는 직접 작성하고 화면에 출력된 내용을 캡쳐한 것이기 때문에, 그대로 따라 작성하시면 동일한 화면을 볼 수 있을 거라 생각이 듭니다.

    다시 한번 작성하신 코드와 본문의 내용을 비교하여 보시고, 그래도 원하는 화면이 표시되지 않는다면, 작성하신 코드를 질문글에 같이 올려주세요. 그리고 화면에 어떻게 표시되는지 설명해주시면 더 좋을 것 같습니다.

    막연하게 "나오질 않는다" 라고만 하시면 제가 문제를 파악할 수가 없습니다.

    감사합니다.

  11. Blog Icon
    김은기

    정말 자세한 사용법 감사드립니다.

  12. 방문해 주셔서 감사드립니다.

  13. Blog Icon
    지나오리

    캬 테이블 사용법을 잘 몰랐는데 아주 자세하게 잘 알려주셔서 감사합니다 -_-)b

  14. 도움이 되셨길 바랍니다.

    감사합니다. ^-^)v

  15. Blog Icon
    안드개발자

    따흐흐흑.. 센세.. 감사합니다

  16. 뜨허허헉.. 에고.. 별말씀을요

  17. Blog Icon

    비밀댓글입니다

  18. 그 정도 칭찬을 받을 글은 아닙니다. ^^
    그래도 격려해주셔서 감사합니다.

  19. Blog Icon
    파파망토

    안녕하세요~ 좋은글 보고 잘 배우고 갑니다~ 한땀한땀 대단한 블로깅에 감탄하고 갑니다 ^^
    다만 한가지 예제와 스샷이 안맞는 부분이 있네요

    테두리 그리기에서 배경은 android:background="#FF0000" 이라고 되어 있는데 실제 선은 빨간색이 안나오네요.
    그리고, 전체 배경색은 TableLayout 에 주는게 아니라 각 TableRow 에 적용하고 마진을 주니까 테두리 적용이 되네요.

    혹시 다른 분들도 헷갈리지 마시라고 적어봅니다~

  20. 오~ 지적하신대로 본문 내용 중에 잘못된 부분이 있군요. 시간 되는대로, 한번 더 확인하고 수정해놓겠습니다.

    본문의 내용을 꼼꼼히 봐주시고, 댓글로 알려주시기까지 해주셔서 감사드립니다. ^^

  21. Blog Icon
    조성환

    tablelayout사용해서 만들었는데
    스마트폰에서는 정상적인 사이즈로 나왔는데
    갤탭에 업로드 하니 사이즈가 절반밖으로 화면이 나타납니다.

    스마트폰이랑 갤탭이랑 동일한 화면형태로 출력하고 싶은데
    어떻게 해야하나요?

  22. 음.. 딱히 그럴만한 내용은 없는데, 어디가 잘못된 걸까요... 이 코드를 테스트 했던 기기가 "Nexus 7 2nd"라서 갤탭과 아주 다르진 않을 것 같은데 말이죠.

    혹시 위치 또는 사이즈 지정하는 속성에 고정 값을 지정하진 않으셨는지 체크해보시기 바랍니다.

    원인을 찾기 힘드시면, 작성하신 XML 코드를 질문글에 올려주시면 도움드리기 용이할 것 같습니다.

    감사합니다.

  23. Blog Icon

    비밀댓글입니다

  24. 흠. 그런 용도라면 굳이 테이블레이아웃을 사용하지 않아도 될 것 같은데요.
    리스트뷰를 쓰시는 게 더 나은 것 같은데. ^^

    일단 행별 클릭을 위해서는, 정확한 답이 될지 모르겠지만, TableRow에 descendantFocusability="blocksDescendants" 속성을 지정해보세요.
    원하시는 답이 되면 좋겠네요.

    감사합니다.

  25. Blog Icon
    예비개발자

    안드로이드 를 지금 공부하는 학생으로서 이런 개념적인 부분이 약한데
    정말 잘보구 갑니다 자주자주 들어 올듯합니다.
    정말로 감사합니다.

  26. 잘 이해되지 않는 부분은 언제든 질문글 남겨주세요.
    최대한 도움 드릴 수 있도록 노력하겠습니다.
    감사합니다.

  27. Blog Icon
    신입

    책으로 출판해도 손색이 없을 정도의 퀄리티입니다 정말 최고네요

  28. 책으로 출판해봐야... 나무에게 미안한 일만 되지 않을까요? ㅜㅜ

    그래도 격려의 댓글 남겨주셔서 힘이 됩니다.

    더 좋은 내용 정리할 수 있도록 노력하겠습니다.

    감사합니다.

  29. 블로그 퀄리티가 너무 좋습니다.
    수업 중 이해 안되는 내용들은 거의 대부분 여기에 있어서 여기서 다시 복습하는 것 같아요.
    질 좋은 내용을 올려주셔서 감사합니다.

  30. 과분한 칭찬글 남겨주셨네요.
    격려의 댓글로 좀 더 힘을 내어, 더 좋은 글 남길 수 있도록 노력하겠습니다.

    감사합니다.

  31. Blog Icon
    할수있다

    너무너무 감사합니다 혼자서 공부하기 가이드라인이 없어서 헤맸는데 너무나 도움이 되었습니다

  32. 도움되셨다니 정말 다행이네요!
    궁금한 내용 있으면 언제든 질문글 남겨주세요.

    감사합니다.