본문 바로가기

안드로이드/팁

[안드로이드/Android] Gridlayout으로 시간표 만들기

반응형

시간표나 달력을 구현할때마다 '이번엔 뭐로 구현해볼까', '어떻게 해야 좀 호율적이고 간단하게 만들 수 있을까?'를 고민 했었습니다. Linearlayout으로 이뤄진 뷰들을 xml에 하나하나 그리고 칸 하나마다 list로 관리하거나 Recyclerview로 만들어서 xml이 적은대신 ItemAdapter나 Viewholder 클래스를 생성하는 방식을 주로 선택했습니다.

그런데 이번엔 Gridelayout 으로 시간표를 만들게 돼, 간단한 사용법과 다른 구현 방법들과 차이점을 정리했습니다.

>> 구현하기

build.gradle ( app )

    implementation "androidx.gridlayout:gridlayout:1.0.0"

xml

Gridlayout 은 Linearlayout이나 Constraintlayout처럼 ViewGroup의 하나로 내부에 선언된 View들이 하나의 column과 row입니다. 이하 문서에선 column을 열, row를 행으로 칭하여 사용합니다.

    <androidx.gridlayout.widget.GridLayout
        android:layout_width="match_parent"
        app:columnCount="3"
        app:rowCount="2"
        app:alignmentMode="alignMargins"
        android:layout_height="match_parent">

        <Button
            android:text="1"
            />

        <Button
            android:text="2"
            />

        <Button
            android:text="3"
            />

        <Button
            android:text="4"
            />

        <Button
            android:text="5"
            />

        <Button
            android:text="6"
            />

    </androidx.gridlayout.widget.GridLayout>
  • app:columnCount : 행의 갯수로 한줄에 몇개의 컬럼이 들어갈지 정합니다.
  • app:rowCount : 열의 갯수로 몇줄의 레이아웃을 그릴지 정합니다.
  • app:orientation : 자식 View들의 정렬 방향을 선택합니다. 

Orientation

자식 View들은 작성된 순서대로 표에 그려지게 되는데 기본 디폴트 값은 horizontal입니다. 

vertical horizontal

alignmentMode 

자식 View들중 기준이 되는 뷰의 마진과 동일하게 정렬할지 정합니다. 기준이 되는 뷰는 같은 줄에 있는 View중에 마진이 제일 큰 값입니다.  값은 alignMargins alignBounds 가 있는데 alignBounds 는 기준이 되는 View와 동일한 마진값을 갖고, alignMargins 는 각자 설정된 마진값을 갖습니다.

그 예로 밑의 코드와 같이 첫번째 뷰의 마진을 20, 두번째 뷰의 마진을 10으로 설정하고, alignmentMode 는 alignBounds 로 설정했을때 첫번째 뷰의 여백을 따라 같은 줄의 뷰들도 마진값을 갖게 됩니다.

    <androidx.gridlayout.widget.GridLayout
        android:layout_width="match_parent"
        app:columnCount="3"
        app:orientation="horizontal"
        app:rowCount="2"
        app:alignmentMode="alignBounds"
        android:layout_height="match_parent">

        <Button
            android:layout_marginTop="20dp"
            android:text="1"
            />

        <Button
            android:layout_marginTop="10dp"
            android:text="2"
            />

        <Button
            android:text="3"
            />

        <Button
            android:text="4"
            />

        <Button
            android:text="5"
            />

        <Button
            android:text="6"
            />

    </androidx.gridlayout.widget.GridLayout>

xml 미리보기

layout_gravity

셀에게 할당된 영역안에서 위치가 조정됩니다. 예를들어 위 사진의 경우 1,2,3번 셀의 넓이는 다 동일하지만 제일 우측에 위치한 3번의 경우 grvity에 따라 위치가 달라지게 됩니다. 

하지만 1번 셀의 경우 gravity를 설정해도 본인의 영역만큼 이미 차지하고 있어서 변화가 없습니다. ( 아래 표 참고 )

fill_horizontal로 지정한 경우  right로 지정한 경우 

layout_row / layout_column

자식 View의 행과 열을 직접 입력해서 위치를 조정할수 있고, 이전에 작성된 뷰와 사이 셀들은 빈 셀들로 채워지게 됩니다.

2번째 셀의 column을 2 row를 1로 지정했을 경우 ( 0부터 시작 ) 1번째 자식 뷰와의 사이는 빈 셀들로 채워지고 그 뒤에 작성된 자식부들은 2번째 뷰와 동일하게 밀립니다. (그림2 참고)

    <androidx.gridlayout.widget.GridLayout
        android:layout_width="match_parent"
        app:columnCount="3"
        app:orientation="horizontal"
        app:rowCount="2"
        app:alignmentMode="alignBounds"
        android:layout_height="match_parent">

        <Button
            android:layout_marginTop="20dp"
            android:text="1"
            />

        <Button
            android:layout_marginTop="10dp"
            android:text="2"
            app:layout_row="1"
            app:layout_column="2"
            />

        <Button
            android:text="3"
            app:layout_gravity="fill_horizontal"
            />

        <Button
            android:text="4"
            app:layout_gravity="fill_vertical"
            />

        <Button
            android:text="5"
            />

        <Button
            android:text="6"
            />

    </androidx.gridlayout.widget.GridLayout>

그림2

rowSpan, columnSpan

각 행과 열의 차지하는 셀의 크기를 지정합니다. 2번 뷰의 columnSpan을 2로 지정했을 경우 같은 행에 있었던 3번째 뷰는 2번째 행으로 밀려납니다.  (그림3 참고) 

    <androidx.gridlayout.widget.GridLayout
        android:layout_width="match_parent"
        app:columnCount="3"
        app:orientation="horizontal"
        app:rowCount="2"
        app:alignmentMode="alignBounds"
        android:layout_height="match_parent">

        <Button
            android:text="1"
            />

        <Button
            app:layout_columnSpan="2"
            app:layout_gravity="fill"
            android:text="2"
            />

        <Button
            android:text="3"
            />

        <Button
            android:text="4"
            />

        <Button
            android:text="5"
            />


    </androidx.gridlayout.widget.GridLayout>

그림3

테두리 지정

시간표와 같이 일부 표를 그릴때 각 셀마다 테두리를 그려줘야 하는 경우가 있습니다. 별도 옵션을 제공하지 않아서 직접 설정해줘야 하는데

저의 경우 1dp의 선을 그려줄 경우 0.5dp에 해당하는 drawble코드를 생성해서 각 셀에 background로 설정합니다.

ex) 1번 셀과 2번셀에 0.5dp의 선을 지정해주면 사이에는 총 1dp의 선이 생성됩니다.

>> 시간표 구현

Gridelayout으로 구현했을때 예상과 같이 xml에 많은 코드를 작성해야 하고 셀을 추가하거나 변경할때 모두 변경 해줘야 하는 번거로움은 있지만 style을 지정해서 한번에 바꿔주는 방법을 사용하면 보완이 가능할것 같습니다. 그리고 뷰의 기본 설정값인 width나 height도 필수 값이 아니기 때문에 생각보다 그렇게 많은 라인을 소모하지 않고 주석을 사용하면 행간 구분도 용이합니다. 

그리고 시간표의 경우 점심시간과 같이 span 설정이 필요할 경우는 recyclerview보단 gridlayout을 활용하는게 더 편합니다. 

반응형