본문 바로가기

안드로이드

안드로이드 Layout Tricks: Merging Layouts

[번역] 안드로이드 Layout Tricks: Merging Layouts  안드로이드

2010/04/01 23:54

복사http://huewu.blog.me/110083649927

Layout Tricks: Merging Layouts

LayoutTricks 의 마지막은 Merge 태그에 관한 이야기입니다. 좀 생소하긴 해도, CustomView 를 생성하고자 할 때, 굉장히 효과적으로 View 계층 구조를 줄여나갈 수 있어서,  알아두면 쏠쏠하게 효과를 볼 수 있을 듯 하네요.

  한 번 작성한 Layout 코드를 공유하고 재사용하기 위해 <include/> 태그를 사용하는 방법에 대하여 이야기 했었다. 이번 글에서는 <include/> 태그를 사용할 때 생기는 문제점을 보완해 줄 수 있는 <merge/> 태그에 관해 이야기해 본다.

 안드로이드에서 UI Layout 을 구성 할 때, View 계층 구조의 단계를 줄여 최적화 하기 위해 <merge /> 태그가 만들어졌다.  예제를 통해 살펴보면, 이 태그를 사용하는 목적에 대해 쉽게 이해할 수 있다. 다음의 예는, 어떤 이미지를 표시하고, 그 이미지 위해 해당 이미지의 제목을 표시해 주는 XML Layout 이다. 구조는 매우 단순하다.  FrameLayout 을 이용해서, ImageView 위에 TextView 를 표시하였다. 

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   
android:layout_width="fill_parent"
   
android:layout_height="fill_parent">

   
<ImageView  
       
android:layout_width="fill_parent"
       
android:layout_height="fill_parent"
   
       
android:scaleType="center"
       
android:src="@drawable/golden_gate" />
   
   
<TextView
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:layout_marginBottom="20dip"
       
android:layout_gravity="center_horizontal|bottom"

       
android:padding="12dip"
       
       
android:background="#AA000000"
       
android:textColor="#ffffffff"
       
       
android:text="Golden Gate" />

</FrameLayout>

 이 Layout 은 원하는 대로 잘 작동하며, 특별히 잘못된 점은 찾을 수 없다.

 하지만 만일 이 레이아웃을 HierarchyViewer 를 통해 살펴보면 흥미로운 점이 들어난다. 개발자가 View 계층 구조를 잘 살펴보면, 우리가 XML 파일에 정의한  FrameLayout 이 딱 하나의  FrameLayout 만을 자식 View 로 가지고 있는 것을 확인 할 수 있다.  (파란색으로 강조되어 있다.)

 이 때 FrameLayout 은 fill_parent 속성 값을 사용하고 있기 때문에, 그 부모와 동일한 영역을 차지한다. 또한, 특별한 배경을 지정하지도 않았으며, 추가적인 Padding 속성이나 Gravity 속성을 지정하지 않았기 때문에, 사실 화면을 구성 하는데 역할을 수행하지 않는다. 즉, 이 경우 추가적으로 사용된 FrameLayout 은 어떠한 이유도 없이 그저 UI 를 보다 복잡하게 만들 뿐이다. 하지만  우리가 어떻게 이 FrameLayout 을 제거할 수 있을까?  어찌되었든, Layout 을 지정하는 XML 다큐먼트는 Root 태그를 가져야 하면,  XML 상에 정의된 태그 는 실제 View 로 구현된다.

 바로 이 경우에 <merge/> 태그가 쓸모있다.  LayoutInflater 가 View 를 형상화 하는 과정 중에, <merge/> 태그를 만나게 되면, 해당 <merge/> 태그는 건너 뛰고,  그 자식 View 들을 <merge/> 태그의 부모 View 에 추가한다. 설명이 조금 헷갈릴 수도 있겠다. 이해를 돕기 위해, 이전 예제에서 사용된 FrameLayout  대신 <merge/> 를 사용한 후 살펴 보자. 

<merge xmlns:android="http://schemas.android.com/apk/res/android">

   
<ImageView  
       
android:layout_width="fill_parent"
       
android:layout_height="fill_parent"
   
       
android:scaleType="center"
       
android:src="@drawable/golden_gate" />
   
   
<TextView
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:layout_marginBottom="20dip"
       
android:layout_gravity="center_horizontal|bottom"

       
android:padding="12dip"
       
       
android:background="#AA000000"
       
android:textColor="#ffffffff"
       
       
android:text="Golden Gate" />

</merge>

  이 새로운 버전의 Layout 에서 TextView 와 ImageView 는  최상위 FrameLayout 에 바로 추가된다. 그 결과, 화면상으로 동일하게 보이지만, 실재 View 계층구조는 좀 더 단순해 진다.

  명백하게도  위의 예제에서 <merge /> 태그를 사용 할 수 있는 것은, Activity 에 사용된  Content View 가 FrameLayout  이기 때문이다. (FrameLayout 이 두 번 반복되기 때문에 하나를 줄일 수 있음)  만일 FrameLayout 대신 LinearLayout 이 Root  태그로 사용되었다면, <merge/> 태그를 사용할 수 없다. 

  하지만 <merge /> 태그는 다른 경우에도 유용하게 사용될 수 있다. 예를 들어, <merge /> 태그는 <include /> 를 통해 View 를 추가하고자 할 때, 완벽하게 작동한다. 또한, XML 상에서 몇개의 View 를 조합하여, 커스텀한 View 를 구성하고자 하는 경우에도 <merge />  태그는 유용하게 사용된다.  Button 내부의 내용을 원하는 대로 수정할 수 있는, 두 개의 Button 을 보여주는 OKCancelBar 라는 CustomView 를 만들 때,  <merge /> 를 어떻게 사용할 수 있는지 한 번 살펴보자. (원한 다면, 이 예제의 완벽한 소스를 다운로드 받을 수도 있다.)  아래의 예제는,  어떤 이미지 위에 우리가 새롭게 정의한 CustomView 를 표시한다. 

<merge
   
xmlns:android="http://schemas.android.com/apk/res/android"
   
xmlns:okCancelBar="http://schemas.android.com/apk/res/com.example.android.merge">

   
<ImageView  
       
android:layout_width="fill_parent"
       
android:layout_height="fill_parent"
   
       
android:scaleType="center"
       
android:src="@drawable/golden_gate" />
   
   
<com.example.android.merge.OkCancelBar
       
android:layout_width="fill_parent"
       
android:layout_height="wrap_content"
       
android:layout_gravity="bottom"

       
android:paddingTop="8dip"
       
android:gravity="center_horizontal"
       
       
android:background="#AA000000"
       
       
okCancelBar:okLabel="Save"
       
okCancelBar:cancelLabel="Don't save" />

</merge>

새로운 Layout 은 다음과 같은 결과를 만들어 낸다.

 새로운 CustomView  인 OKCancelBar 의 소스 코드는 매우 단순하다. 왜냐하면 두 개의 버튼을 생성하기 위한 코드는 외부 XML 파일에 별도로 지정되어 있기 때문이다. 다음 코드에서 확인 할 수 있듯이, R.layout.okcancelbar 에 지정된 Layout 이 LayoutInflate 를 통해 형상화 된 후, OKCancelBar 의 자식 View로 추가된다. 

public class OkCancelBar extends LinearLayout {
   
public OkCancelBar(Context context, AttributeSet attrs) {
       
super(context, attrs);
        setOrientation
(HORIZONTAL);
        setGravity
(Gravity.CENTER);
        setWeightSum
(1.0f);
       
       
LayoutInflater.from(context).inflate(R.layout.okcancelbar, this, true);
       
       
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.OkCancelBar, 0, 0);
       
       
String text = array.getString(R.styleable.OkCancelBar_okLabel);
       
if (text == null) text = "Ok";
       
((Button) findViewById(R.id.okcancelbar_ok)).setText(text);
       
        text
= array.getString(R.styleable.OkCancelBar_cancelLabel);
       
if (text == null) text = "Cancel";
       
((Button) findViewById(R.id.okcancelbar_cancel)).setText(text);
       
        array
.recycle();
   
}
}

 두 개의 버튼은 다음의 XML Layout에 정의되어 있다. 추가적인 Layout 없이, 부모 View 인 OKCancelBar 에 두 개의 버튼을 직접 추가하기 위해서 <merge /> 태그를 사용했다. 또한, 개별 버튼은 유지하고 관리하기 쉽게 하기 위해,  외부 XML 파일에 별도로 구현된 후, <include/> 태그를 이용해 두 번 포함되었고, 단순히 id 값만을 Override 하였다. 

<merge xmlns:android="http://schemas.android.com/apk/res/android">
   
<include
       
layout="@layout/okcancelbar_button"
       
android:id="@+id/okcancelbar_ok" />
       
   
<include
       
layout="@layout/okcancelbar_button"
       
android:id="@+id/okcancelbar_cancel" />
</merge>

  결과적으로 우리는, 효율적인 View 계층 구조를 갖으면서도, 유연하고 유지보수 하기 쉬운 Custom View 를 작성 하였다. 

 살펴본 봐와 같이, <merge/> 태그는 코드를 작성할 때, 굉장히 유용하며 깜짝 놀랄만한 일들을 해 준다. 하지만, 몇 가지 한계점도 갖고 있다.