본문 바로가기

Android/안드로이드 스튜디오

안드로이드 스튜디오> 레이아웃(layout) 기초

레이아웃 기초

 

뷰와 뷰그룹을 이용하여 레이아웃을 구성하려면 두 가지 방버 중 하나를 이용해야 합니다. 하나는 XML로 UI 요소를 구성하는 것이고, 또 하나는 레이아웃 요소를 직접 코팅해야 합니다.

 

자바 코드로 레이아웃을 구성하면 실행 중(Run-time)에 레이아웃을 동적으로 배치하고 조작 할 수 있습니다.

 

안드로이드 프레임워크에서는 애플리케이션의 UI를 선언하고 관리하기 위한 방법을 둘 중 하나 또는 둘 모두를 사용 수 있도록 제공합니다. 예를 들어 XML로 기본 레이아웃을 구성하여 기본 속성을 정의하고, 자바 코드로 특정 버튼을 눌렀을 때 화면에 메시지가 표시되는 등 속성을 변경할 수 있습니다.

 

UI를 XML로 선언하는 것은 이점은 로직과 레이아웃을 분리할 수 있다는 것입니다. 이렇게 하면 개발자의 유지보수가 쉬워지고, 레이아웃만 수정했을 때 자바 코드를 따로 컴파일하지 않아도 됩니다. 그리고 서로 다은 방향, 크기, 언어에 대해 각각 XML 레이아웃을 다르게 생성할 수 있고, XML은 구조를 시각화하기 쉬워서 디버깅하기도 쉽습니다. 

 

 

레이아웃의 작성

 

안드로이드에서는 XML 문법을 사용하여 UI 레이아웃과 그 안에 들어있는 화면 요소를 HTML에서 웹페이지를 디자인할 때와 같은 방식으로 신속하게 디자인할 수 있습니다.

<TextView
     android:layout_width="200dp"
     android:layout_height="100dp"
     android:text="Hello World"
     android:background="@android:color/dark_gray" />

TextView 태그의 속성으로 android:layout_width 등이 있고 속성값은 큰따옴표(" ")로 둘러싸여 있습니다. 속성 앞에 android:는 이름공간(namespace)이며, 모든 기본 속성에 반드시 포함되어야 합니다. 

 

속성값은 = 기호 다음에 큰따옴표로 둘러싸고 마지막에는 태그를 닫아야합니다.

<TextView>로 연 태그는 </TextView>로 닫아야하지만 TextView와 같은 일반뷰는 자식 뷰를 가질 수 없으므로  <TextView />로 닫는 태그를 대체할 수 있습니다.

 

UI 요소를 선언하는 데 쓰이는 XML 문법은 자바에서의 클래스와 메서드 명명규칙을 따릅니다. 요소의 이름(TextView)은 클래스와 매칭되고, android:text와 같은 속성 이름은 메서드와 매칭됩니다. TextView에는 text 속성이 있으며 이는 TextView 자바 클래스의 setText() 메서드와 매칭된다고 생각하시면 됩니다.

 

각 레이아웃 파일에는 반드시 딱 하나의 루트 요소만 있어야 하며, 이는 View 또는 ViewGroup 객체여야 합니다. 루트 요소를 정의했으면, 하위 요소로 더 많은 레이아웃 요소(뷰나 뷰그룹)를 추가하여 레이아웃을 구성할 수 있습니다. 아래 예는 수직으로 자식뷰들을 배치할 수 있는 뷰그룹인 LinearLayout을 사용하여 글자를 표시하는 TextView와 Button을 가지는 XML 레이아웃을 나타낸 것입니다.  

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView android:id="@+id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello" />

    <Button android:id="@+id/Button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1 />
</LinearLayout>

LinearLayout의 orientation="vertical" 속성은 자식 뷰들을 수직으로 배치합니다. 수평 배치는 horizontal 속성을 적용하면 됩니다. layout_width와 layout_height 속성에는 가로, 세로 길이는 정의할 수 있으며 match_parent와 wrap_content 또는 임의의 수치(200dp) 중 한가지를 설정할 수 있습니다.

 

match_parent는 부모 뷰의 크기에 맞게 꽉 채우는 것이며, wrap_content는 현재 뷰의 내부 콘텐츠 크기에 맞게 최대한 작게 만듭니다. 그리고 임의이 값을 dp 단위로 설정할 수도 있는데 dp단위는 서로 다른 해상도나 빌드를 가진 기기 간에도 동일한 크기로 보이게 하는 단위입니다. 

이러한 레이아웃은 XML 파일로 만들어 Android 프로젝트의 res/layout/ 디렉토리에 .xml 확장자로 저장합니다.

 

 

XML 리소스 로딩

 

앱을 컴파일할 때 각 XML 레이아웃 파일도 컴파일 하는데 레이아웃 리소스는 액티비티의 onCreate() 메서드에서 불러와야합니다. 이렇게 하려면 setContentView()에 R.layout.[레이아웃 파일명] 형태의 피라미터를 전달하여 호출합니다. XML 레이아웃이 main_layout.xml로 저장되었다면 이것을 액티비티에 불러오려면 다음처럼 작성합니다.

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.mian_layout);

onCreate() 메서드는 안드로이드 프레임워크에서 앱이 실행되어 액티비티가 생성될 때 호출되는 콜백 메서드입니다. 안드로이드의 시작점입니다.

 

 

속성(attribute)

 

모든 뷰와 뷰그룹 객체는 다양한 속성을 지원합니다. 속성에는 공통 속성과 각 뷰만이 가지고 있는 전용 속성이 있는데 모든 뷰 객체에는 정수 타입의 id를 설정할 수 있습니다. 이 뷰 id는 뷰를 식별하기 위한 식별자로 사용됩니다. 그래서 모든 id는 고유(unique)합니다. XML 파일에서 일반적으로 눈자열을 할당하면 됩니다. 그러면 앱이 컴파일되면서 id가 R.java라는 파일에 정수로 생성되어 내부적으로 정숫값을 사용하게 됩니다.

android:id="@+id/my_button

문자열 시작부분에 골뱅이 기호(@)가 필요하고, 더하기 기호(+)는 이것이 새로운 리소스 이름임을 알 수 있습니다. 우리가 작성한 id가 아닌 기본적으로 안드로이드 프레임워크가 제공하는 id 리소스를 사용해야 하는 때가 있는데, 이때는 android 네임스페이스를 추가해야합니다.

android:id="@android:id/empty

내가 작성하고 정의한 리소스는 R.java 파일에 생성되고, 안드로이드 플레임워크가 제공하는 리소스는 android.R.java 파일을 참조하면 됩니다.

 

뷰를 추가하는 보편적인 패턴은 레이아웃 파일에서 뷰 중 하나를 추가하고 고유한 id를 할당합니다.

<Button android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/Button Example" />

정의한 id를 통해서 자바 파일에서 뷰 객체의 인스턴스를 생성하고이를 레이아웃과 연결한니다. 이때 Activity 클래스에서 제공하는 findViewById() 메서드를 사용하여 원하는 뷰의 인스턴스를 얻을 수 있습니다.

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.mian_layout);
  
  Button myButton = (Button) findViewById(R.id.my_button)
}

findViewById() 메서드는 setContentView()에 전달된 레이아웃(R.layout.mian_layout)에서 id가 있는지 검색합니다. 찾는 id를 가지고 있는 뷰가 있으면 반환하고, 없으면 null을 반환합니다. 반환된 뷰는 원래 사용하려는 형태로 강제 캐스팅합니다. id는 전체 앱에서 고유할 필요는 없지만, 각 XML 안에서는 고유해야 합니다. R.java 파일에는 각각 다른 정수값으로 생성됩니다.

 

 

마진(margin) 과 패팅(padding)

 

모든 뷰는 여백을 가질 수 있는데 마진과 패딩 두가지 종류가 있습니다. 마진은 뷰 바깥쪽 여백을 말하고 패딩은 뷰 안쪽 여백입니다.

마진을 주면 뷰 외부에 여백이 생기고 패딩을 주면 내부에 여백이 생기고 이때 단위는 dp를 사용합니다.

 

마진은 layout_margin, 패딩은 padding 속성을 사용합니다. 아래의 예를 참고하시기 바랍니다.

 

 <!--padding 적용한 예-->
 <!--TextView의 테두리로부터 text의 사이에 20dp의 여백을 가진다.-->
 <TextView
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:padding="20dp"
     android:text="padding 적용한 예"

 <!--margin 적용한 예-->
 <!--부모레이아웃과 TextView 위젯에 20dp의 여백을 가진다.-->
 <TextView
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_margin="20dp"
     android:text="margin 적용한 예"

android:layout_margin="20dp"

네 방향으로 여백을 20dp 설정

 

android:layout_marginStart="20dp"

시작 방향으로 여백을 20dp 설정

 

android:layout_marginEnd="20dp"

끝 방향으로 여백을 20dp 설정

 

android:layout_marginRight="20dp"

오른쪽 방향으로 여백을 20dp 설정

 

android:layout_marginLeft="20dp"     

왼쪽 방향으로 여백을 20dp 설정

 

android:layout_marginTop="20dp"

위쪽 방향으로 여백을 20dp 설정

 

android:layout_marginBottom="20dp"  

아래쪽 방향으로 여백을 20dp 설정

 

 

우리나라에서는 왼쪽에서 오른쪽으로 글을 쓰기 때문에 시작과 끝도 왼쪽, 오른쪽과 매칭됩니다. API17  이상에서는 Start, End를 사용하면 각 국가에 맞게 기준이 자동으로 변경됩니다.