안드로이드 기본 레이아웃 사용법

ViewGroup을 상속하여 만든 다양한 레이아웃을 안드로이드에서는 기본제공한다. 기본으로 제공하는 레이아웃은 다양한 스마트폰과 테블릿에서 확장 가능한 애플리케이션을 만들 수 있도록 설계되었다. 이번 장에서는 여러 스마트폰 크기를 지원하기 위해 레이아웃과 뷰의 배치방법에 대해 소개하며, 기본으로 제공하는 레이아웃들의 특징을 살펴 보겠다.

안드로이드는 다양한 크기와 형태를 지원하기 위해서 레이아웃을 절대 픽셀 위치를 주는 것은 대단히 위험한 일이다. 항상 레이아웃의 크기는 변할 수 있다는 것을 잊어서는 안된다. 그렇기 때문에 레이아웃은 고정된 영역과 확장 가능한 영역을 정의해야 한다. 고정된 영역은 사용자가 터치를 하는 아이콘이 될 수 있으며 그 크기는 고정된다. 확장 가능한 영역은 고정된 영역과 반대로 공간을 채우기 위해 크기가 조정되는 부분이다.

<그림 3.0.1> 레이아웃의 고정된 영역과 확장가능한 영역 분리

예를 들어 액션바에 아이콘을 배치하는 경우 아이콘의 고정된 크기를 유지하기 위해 액션바의 높이는 고정된 높이를 가지게되며, 수평으로 전체 화면을 채우기 위해서는 넓이는 조정되어야 한다. 그림 3.0.1에서 보듯이 확장가능한 영역과 고정된 영역을 정의한 모습이다. 이렇게 레이아웃의 영역을 정의하면 그림 3.0.2에서 처럼 레이아웃의 크기가 변경 되어도 대응 할 수 있다.

<그림 3.0.2> 확장/축소 가능한 영역으로 인한 다양한 사이즈의 대응

이 처럼 다양한 사이즈에 대응하기 위해 고정된 영역과 확장 가능한 영역을 나누었다. 이렇게 화면을 구성하기 위해 기본적인 레이아웃을 안드로이드에서 제공하고 있다.


3.1 LinerLayout

일반적으로 안드로이드에서 가장 흔하게 쓰는 레이아웃 중 하나이다. 레이아웃 내부에 배치되는 뷰는 수평 또는 수직으로 나란하게 배치된다. 수평인지 수직인지 레이아웃의 방향을 설정하여 사용해야 하며, 내부에 배치되는 뷰들 간의 크기를 상대적으로 구성 가능 하다. 화면의 사이즈가 모두 다른 경우 각각의 화면에 최적화 하기 위해서 가장 필요한 레이아웃이다.

화면의 크기에 상관 없이 버튼을 화면의 비율에 맞게 각각 다른 크기로 3개를 나눈다고 생각 해보자. 이런 경우 고정된 높이를 지정하게 되면 화면의 크기가 더 커지거나 작아지는 경우 공간이 남거나 짤리게 된다. LinerLayout의 가중치를 이용하면 화면의 크기와 상관 없이 비율에 따라 내부에 배치되는 뷰의 크기가 비율에 맞게 크기가 동적으로 변한다.

코드 3.1.1은 내부에 배치될 layout_orientation속성의 값을 vertical로 주어 세로로 나란히 배치하게 하였다. 그리고 내부에 배치될 버튼의 layout_weight속성 값을 각각 1, 2, 3으로 주었다. 이렇게 가중치값을 통해 각각의 버튼들은 1:2:3의 크기로 높이가 정해진다.

그림 3.1.1에서 보듯 LinearLayout의 레이아웃의 높이는 layout_weight속성의 값에 따라 바뀌게되는 것을 볼 수있다. 화면의 크기에 상관없이 정해진 비율로 LinearLayout 내의 뷰들이 크기가 정해진다.

<그림 3.1.1> LinearLayout의 비율에 따른 높이 변화

layout_weight값을 이용하면 그림 3.0.2에서 설명한 확장/축소 가능한 영역을 지정할 수 있기 때문에 다양한 스크린 사이즈에 대응할 수 있다. 코드 3.1.2는 확장/축소가능한 영역인 텍스트를 감싸고 있는 LinearLayout의 layout_weight속성에 항상 꽉차도록 하기위해 1의 값을 주었다. 나머지 이미지와 버튼은 고정된 영역이기 때문에 별도로 layout_weight속성을 주지 않았다.

레이아웃을 실행 하게 되면 텍스트를 감싸고 있는 LinearLayout부분은 가로로 항상 꽉 차게 되며 왼쪽 아이콘과 오른쪽 버튼은 고정된 크기만큼 자리를 차지하게 된다. 그림 3.1.2에서 스크린의 가로와 세로 또는 화면의 스크린 사이즈에 관계 없이 다양한 화면에 대응할 수 있는 기본적인 구조를 가지는 것을 볼 수 있다.

<그림 3.1.2> LinearLayout의 가중치를 이용한 다양한 스크린 사이즈 대응

LinearLayout은 내부의 뷰를 가로 또는 세로로 배치하며, 가중치를 통해서 다양한 스크린사이즈에 대응 할 수 있는 안드로이드에서 가장 많이 쓰이며 반드시 알아야 할 레이아웃이다.


3.2. RelativeLayout

RelativeLayout도 LinearLayout과 마찬하기로 가장 흔하게 쓰이는 레이아웃이다. 내부의 뷰를 중첩된 형태로 구성이 가능하며 부모뷰 또는 같은 자식뷰들의 영역 대해 상대적인 위치를 지정 할 수 있다. 예를 들면 부모뷰를 기준으로 가운데 정렬을 하거나 하단/상단, 오른쪽/왼쪽으로 정렬 할 수 있다. 또한 자식뷰를 기준으로 왼쪽, 오른쪽, 상단, 하단으로 정렬 할 수 있다.

코드 3.2.1은 부모뷰를 기준으로 정렬하는 예제이다. 뷰모뷰인 RelativeLayout은 화면에 꽉 차도록 크기가 지정되었으며, 5개의 버튼은 각각의 정렬될 속성의 값을 주어 정렬 시켰다.

여기서 중요한 점은 화면 스크린의 크기에 상관없이 뷰모뷰를 기준으로 정렬 되기때문에 그림 3.2.1과 같이 정렬된다. RelativeLayout의 layout_alignParent속성을 이용하면 다양한 화면 스크린에 대해 쉬운 방법으로 대응 가능하다.

<그림 3.2.1> RelativeLayout의 뷰모뷰 기준의 정렬 방식

뷰모뷰를 기준으로 정렬되는 방식 뿐만 아니라 자식뷰간의 관계를 통해서 정렬되는 방식도 있다. 자식간의 뷰를 구분하기 위해서 자식의 아이디 값을 통해서 정렬된다. 코드 3.2.2는 버튼 하나를 부모 뷰를 기준으로 정가운데 배치후에 @+id/button_center라는 고유 아이디를 정해 주었다. 이 고유 아이디를 기준으로 4개의 방향으로 4개의 버튼을 배치 시켰다.

각각의 버튼은 layout_toLeftOf, layout_toRightOf, layout_above, layout_below속성을 통해 Center버튼을 기준으로 위치하게 된다. 그림 3.2.2 왼쪽 그림은 Center버튼을 기준으로 위치해 있을 뿐 정렬이 되지 않아 RelativeLayout의 기본 위치인 왼쪽 상단으로 배치 된 것을 볼 수 있다. 정렬된 기준도 같은 위치에 배치하기위해 layout_align속성을 사용하여 정렬하게 되면 그림 3.2.2 오른쪽 그림과 같이 정렬 되게 된다.

<그림 3.2.2> RelativeLayout의 자식뷰 정렬 방식

이렇게 부모뷰 또는 자식뷰 간의 상대적인 위치를 통해 정렬하지 않고 자신뷰를 중첩 형태로 구성이 가능하다. 코드 3.2.3은 RelativeLayout에 배경이 들어 있는 이미지를 배치 하여 중첩 시킨 구조이다.

그림 3.2.3은 이미지뷰가 중첩되어 그려진 것을 볼 수 있다. 중첩되는 위치는 시스템에서 레이아웃 XML 문서를 읽는 방식에 있는데, 위쪽에서 아래쪽으로 읽혀 지기때문에 가장 위쪽에 있을 수록 뷰는 처음에 그려져 하단에 배치되며 아래쪽으로 있으면 뷰는 나중에 그려져 상단에 배치 된다.

<그림 3.2.3> RelativeLayout의 자식뷰 중첩 방식


3.3 FrameLayout

FrameLayout은 아주 단순한 레이아웃으로 보통 하나의 자식뷰 또는 레이아웃을 배치시키나 경우에 따라 더 많이 배치시키는 경우도 있다. 방금 설명한 RelativeLayout과 마찬가지로 내부에 들어가는 자식뷰들이 중첩된다. 또한 layout_gravity속성을 이용하면 뷰모뷰에 대한 자식뷰의 상적인 배치도 가능하다.

리스트뷰에 데이터를 가져오는 중에는 로딩화면을 보여줄경우 FrameLayout을 사용하여 간단히 처리가능하다. 코드 3.3.1 은 FrameLayout에 뷰를 리스트뷰와 로딩화면을 중첩해 놓은 다음 작업중일때는 로딩화면을 보이 하고 있고, 처리가 완료되면 로딩화면을 숨겨 리스트뷰가 보이도록 하는 아주 일반적인 구조이다.

실제로 FrameLayout을 이용한 구조는 리스트뷰를 쉽게 사용하기위해 만들어진 ListActivity또는 ListFragment에서 로딩화면을 보여주는 방식으로 사용된다. 아주 간단한 구조이기 때문에 플레그먼트를 구성할때도 많이 쓰인다.


3.4 TableLayout

TableLayout은 LinearLayout을 상속받아 구현된 레이아웃으로 경계선을 표시 하지 않는 행과 열의 가지는 격자 형태로 뷰를 정렬하는 레이아웃이다. 일반적으로 표에 뷰를 배치한다고 생각 하면 쉬우며 열과의 병합은 되나 행과의 병합은 되지 않는다. 행은 TableRow를 이용해서 하나의 행을 만들 수 있으며 내부에 뷰를 배치하면 하나의 열이 만들어지는 구조이다. 이때 TableRow중에 가장 많은 열의 개수는 테이블 내의 전체 열의 개수가 된다. 다양한 속성을 통해 특정 열을 숨기거나 화면에 꽉 차도록 늘리거나 줄이는 기능들이 있다.

코드 3.4.1은 TableLayout의 TableRow를 통해 4개 행을 배치하고 각각의 행에 버튼을 다양한 갯수로 열을 배치하였다.

기존의 레이아웃에서 반드시 뷰의 넓이와 높이 값을 주어야 했었으나 TableRow의 내의 뷰는 넓이와 높이 값을 별로도 주지 않아도 된다. TableRow의 내부의 뷰로 화면을 채우기에 작은 경우에 layout_stretchColumns속성을 이용하여 뷰를 늘려 채우게 가능하며 많은 경우에는 layout_shrinkColumns속성을 이용하여 뷰를 줄여 화면에 맞게 조정 가능하다. 그림 3.4.1에서 뷰로 화면에 채우지 못하지만 layout_stretchColumns속성을 통해 0~3까지의 값을 주어 균등하게 늘어난 것을 볼 수 있다. 균등하게 늘어나지 않고 특정 열만 늘어 나게 하고 싶으면 특정 열의 값을 주면 된다.

<그림 3.4.1> TableLayout 예제 실행

LinearLayout과 RelativeLayout에서 설명한 다양한 화면을 지원하기 위한 기본적인 구조를 가진다고 볼 수 있다. TableRow내의 뷰에서 layout_span속성을 이용하면 열을 병합도 가능하다. 이처럼 TableLayout은 TableRow과 같이 사용되며 다양한 속성을 통해서 명확하게 뷰를 배치할 수 있다.


3.5 GridLayout

안드로이드 4.0(API 14)부터 지원하는 레이아웃으로 지정된 행과 열로 격자 방식으로 자식뷰를 정렬하는 방식이다. 3.1에서 설명한 LinearLayout은 수평 또는 수직으로 정렬이 가능하나 수평과 수직을 동시에 정렬하기 위해서는 중첩해서 사용해야 하기때문에 계층구조가 복잡해짐과 동시에 성능 문제도 발생한다. 또한 TableLayout은 TableRow를 사용해야 하기때문에 계층구조가 복잡해지고 행과의 병합이 되지 않는다. 기존의 레이아웃의 문제를 개선하기 위해 행과 열을 격자에 따라 자유롭게 정렬을 제어 할 수 있게 하고 이로 인해 중첩을 피할 수 있는 구조로 설계되었다. TabletLayout과 마찬가지로 내부의 뷰들은 크기가 자동으로 지정되기때문에 넓이와 높이를 설정하는 layout_height와 layout_width값을 설정 할 필요는 없다.

코드 3.5.1은 GridLayout의 장점을 가장 잘 보여주는 예제이다. layout_columnCount 속성을 통해서 열이 5개라는 것과 layout_orientation을 통해서 가로순으로 배치하는 것으로 설정 한다. 이렇게 속성을 지정하게 되면 내부에 들어갈 자식뷰는 순차적으로 가로순으로 5개의 열에 배치되는 것이 기본적인 GridLayout의 형식이다. layout_columnCount외에도 layout_rowCount도 있는데 행의 갯수를 지정하는 것이며, 이때 두개를 동시에 속성을 설정하게 된다면 내부에 들어가는 자식뷰들은 가변적이기 때문에 동시에 설정되지 않고 하나만 설정된다.

내부에 들어가는 뷰들은 기본적으로 지정된 갯수에 따라 하나의 행또는 열에 배치된다. 하지만 layout_rowSpan, layout_columnSpan속성을 이용하면 행 또는 열의 크기를 지정 할 수 있다. 그림 3.5.1에서 2번째 버튼은 rowSpan속성의 값을 2로 주어 2개의 열이 합쳐진 것을 볼 수 있다. 이때 layout_gravity속성을 통해 2번째 공간을 3번째로 합칠지 또는 기본속성인 공간만 비울지 설정 할 수 있게된다. 5번째 버튼은 기본속성으로 layout_gravity에 별도의 값을 주지 않아 하나의 열의 공간만 비워져서 있다.

<그림 3.5.1> GridLayout의 사용 예제

이처럼 GridLayout을 이용하게되면 가상의 격자에서 원하는 위치에 자식뷰를 배치할 수 있는 구조이기 때문에 중첩구조를 사용하는 복잡한 레이아웃의 경우 좀 더 간단하게 만들 수 있다. 하지만 LinearLayout과 RelativeLayout과 같이 화면의 크기가 가변적인 상황에 유용하지 않다. 코드 3.5.2는 텍스트가 화면의 크기가 동적인 상황에 대해서 어떻게 처리하는지를 알아보기위해 3개의 열로 가로로 정렬되게 하였다.

텍스트의 크기가 변화되고 버튼과 이미지들은 양옆으로 고정되어 있어야 다양한 화면의 크기에 대응을 할 수 있는 기준이 된다. 그림 3.5.2의 가로모드에서는 왼쪽 이미지와 오른쪽 버튼이 화면에 맞게 표현되었지만 세로모드는 텍스트가 짤려 표현된 것을 볼 수 있다. GridLayout은 내부 자식뷰들 내에 표시되는 컨텐츠에 따라 뷰의 크기가 정해지기 때문에 LinearLayout처럼 화면의 크기가 가변적인 상황에 사용하지 못하는 단점이 있다.

<그림 3.5.2>

GridLayout은 내부 자식뷰의 크기가 정해져 있는 구조에서 LinearLayout 또는 TableLayout등의 단점인 중첩을 피할 수 있는 가장 최적화된 레이아웃이다.

“안드로이드 기본 레이아웃 사용법”에 대한 2개의 생각

댓글 남기기