안드로이드 UI 구성의 가장 기본적인 개념은 뷰와 뷰 그룹이다.

뷰(View)

뷰(View)는 앱 안에 들어가는 각각의 화면 구성 요소를 의미한다. 안드로이드 앱에서 흔히 볼 수 있는 버튼, 텍스트 등의 UI 구성 요소가 모두 뷰에 해당된다.

뷰는 역할에 따라 다음과 같이 부르기도 한다.

  • 위젯(Widget) : 컨트롤의 역할을 하는 것

  • 레이아웃(Layout) : 내부에 포함된 뷰를 배치하는 역할을 하는 것

뷰 그룹(View Group)

뷰 그룹(View Group)은 여러 개의 뷰를 포함하는 요소이다. 뷰 그룹을 이용해 안에 들어간 뷰의 위치를 지정할 수 있다. View 클래스는 모든 뷰의 최상위 클래스이다. 따라서 뷰와 뷰 그룹은 모두 View 클래스를 상속받기 때문에 뷰 그룹은 뷰처럼 다룰 수 있고, 뷰 그룹 안에 또다른 뷰 그룹이 포함될 수도 있다. 이는 아래의 계층도를 보면 보다 쉽게 이해할 수 있다.

출처 : 부스트코스 안드로이드 프로그래밍

이러한 특징으로 인해, 하나의 뷰를 다른 뷰로부터 상속받아 사용할 때 다른 뷰의 속성을 동일하게 사용할 수 있다.

XML 레이아웃의 구성

사용자에 눈에 보일 화면을 정의하는 레이아웃 파일은 XML 파일로 되어있다.
XML 파일은 태그와 속성으로 구성된다. <> 기호로 태그의 이름을 감싸고, 태그의 내부에 속성을 선언하는 식이다. 속성이 여러개일 경우 공백으로 값을 구분한다.

<시작 태그
  속성1="속성값1"
  속성2="속성값2"
  ...
</종료 태그>

버튼 위젯을 선언하는 경우를 예시로 들면 아래와 같은 형태가 되겠다.
Button은 태그의 이름, android:layout_width는 태그의 속성이다.

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="버튼1" />

태그 안에 또다른 태그를 포함할 필요가 없다면 위와 같이 /> 기호로 종료 태그를 생략할 수 있다.

태그의 이름은 Button, TextView 처럼 안드로이드 API에 기본적으로 정의된 태그라면 패키지를 생략하고 곧바로 사용이 가능하다.
만약 외부 라이브러리나 직접 커스텀한 뷰를 선언한다면 태그 이름에 패키지명을 함께 명시해야 한다.

<android.support.design.widget.CoordinatorLayout 
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  ...
</android.support.design.widget.CoordinatorLayout>

뷰의 속성

뷰에는 개발자가 원하는 상태에 따라 다양한 종류의 속성을 부여할 수 있다.

 

자주 쓰는 뷰의 속성

속성 설명
layout_width 뷰의 폭을 설정한다.
layout_height 뷰의 높이를 설정한다.
id 뷰의 Id를 설정한다.

 

뷰의 크기

이러한 속성 중에서도 필수로 선언되어야 하는 속성은 크기다. 뷰는 뷰를 포함하는 뷰그룹이 가지는 여유 공간의 일부 또는 전체에 놓이게 된다. 화면에서 뷰 하나 하나가 얼마만큼의 공간을 차지할 것인지 계산을 해야하기 때문에, 크기에 대한 선언이 빠지면 에러가 발생하게 된다.
크기는 layout_width, layout_height 두개의 속성으로 선언할 수 있다. 값은 아래의 세가지 중 하나의 값을 가진다.

  • match_parent : 남아있는 여유 공간을 꽉 채운다

  • wrap_content : 뷰에 들어 있는 내용물의 크기에 따라 뷰의 크기를 결정한다

  • 정수값 : 크기를 고정된 값으로 만든다. 사용할 수 있는 단위는 dp, in, mm, pt, px, sp가 있다.

 

사용 가능한 단위

단위 설명
px 화면 픽셀에 따라 크기를 나타낸다.
dp, dip 160dip 화면을 기준으로 한 픽셀. 해상도에 비례하여 비슷한 크기로 보이게 한다.
sp 글꼴을 기준으로 텍스트 크기를 나타낸다.
in 인치로 된 물리적 길이.
mm 밀리미터로 된 물리적 길이.
pt 1/72인치 정도의 물리적 길이.

 

이중 가장 많이 사용되는 단위는 dp이다. dp를 사용했을 때 만약 디스플레이가 320dpi라면 1dp = 2px 이 된다. 이 단위를 사용하면 화면 해상도에 따라 뷰의 크기를 일일이 바꿔줄 필요가 없다.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="폭: wrap_content / 높이: wrap_content" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="폭: match_parent / 높이: wrap_content" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:text="폭: wrap_content / 높이: match_parent" />
</android.support.design.widget.CoordinatorLayout>

위와 같이 작성된 3개의 버튼을 비교했을 때, wrap_content을 사용했을 때는 내용물인 text에 따라 크기가 유동적으로 결정되고, match_parent의 경우 부모 뷰인 LinearLayout의 남은 공간을 무조건 꽉 채우게 된다는 것을 알 수 있다.

세번째 버튼의 경우 부모 뷰에서 이미 다른 뷰가 차지하는 영역이 존재하므로 그 부분을 제외한 나머지 공간을 여유 공간으로 인식하여 배치가 되었다.

 

wrap_content, match_parent, dp를 이용해 크기를 지정하는 이유는 무엇일까?

이는 여러 종류의 스마트폰 크기에 대응하기 위함이다. 안드로이드 운영체제를 사용하는 스마트폰은 워낙 그 크기가 가지각색이다. 단말기마다 크기가 다르더라도 전체 화면을 기준으로 뷰를 배치한다면 더 쉽게 여러 단말의 해상도를 지원할 수 있다.