Blessing Venus

커스텀뷰를 구성하는 레이아웃의 마진을 동적으로 변경해 보자. 본문

Tip&Tech/Android

커스텀뷰를 구성하는 레이아웃의 마진을 동적으로 변경해 보자.

Blessing Venus 2017. 4. 1. 20:54

 

 

우리는 프로젝트나 혹인 개인 앱을 개발하다 보면 동적으로 뷰를 생성하거나,  
커스텀뷰를 생성하여 사용해야만 하는 경우가 생긴다.
때로는 뷰의 마진을 적절한 상황에 맞게 마진을 동적으로 변경해야 하는 상황도 생긴다.
만약 우측 마진을 동적으로 변경하려 할때 커스텀뷰의 XML 구조가 아래와 같다고 가정해 보자.

<RelativeLayout
android:layout_width="155dp"
android:layout_height="155dp">

<ImageView
android:id="@+id/layout_customview_wirteqna_advice_imageView"
android:layout_width="155dp"
android:layout_height="155dp"
android:scaleType="centerCrop"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />

<Button
android:id="@+id/layout_customview_wirteqna_advice_del_button"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:background="@drawable/edit_btn_del" />
</RelativeLayout>

XML 구조가 위와 같은 상황이라 가정해 보자. 

이 XML의 최상위 루트인 RelativeLayout에 마진을 동적으로 주기 위해 아래와 같은 작업을 시도해본다.

LayoutParams layoutParams = new LayoutParams(300, 300);
layoutParams.rightMargin = 100;
mView.setLayoutParams(layoutParams);
위와 같은 로직으로 구현하여 테스트를 해보면 전혀 적용이 되지 않는 것을 확인 할 수 있다.
그럼 두번째 방법으로 아래와 같이 다시 시도해보자.
LayoutParams layoutParams = (LayoutParams)mView.getLayoutParams();
layoutParams.rightMargin = 100;
mView.setLayoutParams(layoutParams);
이 방법조차 안되는 것을 확인 할 수 있다. 
오히려 동작이 되지 않거나 죽어버릴 것이다.

 

왜 안되는 것일까?

 

결론부터 말하면 동적으로 마진을 주는 뷰를 감싸는 부모가 없기 때문에 그렇다.
최상위 부모 뷰에는 마진을 동적으로 할당 할 수 없고, getLayoutParams()는 자신을 감싸는 부모 뷰를 기준으로 자신의 LayoutParams를 리턴해준다.
현재 상황은 최상위 부모 뷰에 마진을 동적할당 하거나 최상위 부모뷰의 LayoutParams를 얻어오려 하기 때문에 두가지 로직 모두 동작하지 않는 것이다.
이제 이를 해결해보자.

XML구조를 아래와 같이 조금만 수정해 보자.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ffffff">
<RelativeLayout
android:id="@+id/layout_customview_writeqna_advice_rootLay"
android:layout_width="155dp"
android:layout_height="155dp">

<ImageView
android:id="@+id/layout_customview_wirteqna_advice_imageView"
android:layout_width="155dp"
android:layout_height="155dp"
android:scaleType="centerCrop"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />

<Button
android:id="@+id/layout_customview_wirteqna_advice_del_button"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:background="@drawable/edit_btn_del" />
</RelativeLayout>
</LinearLayout>

이전의 우리가 동적으로 마진을 변경하려던 레이아웃 위에 LinearLayout을 하나 두어 우리가 동적으로 마진을 할당해야 할 레이아웃을 감싸도록 하자.
이제 우리가 동적으로 마진을 할당할 레이아웃이 Child가 될 수 있도록 해보자.

이를 위해서 RelativeLayout을 LinearLayout이 감싸는 구조로 변경하였다.

 

또한 RelativeLayout을 객체화 시켜 getLayoutParams()를 이용하여 LayoutParams를 얻어 올 수 있도록 해보자.

이것이 가능하게 하기 위해 해당 레이아웃 뷰에 임의의 ID값을 할당하였다.

이제 동적으로 마진을 변경해보자.
String infService = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(infService);
mView = layoutInflater.inflate(R.layout.layout_customview_writeqna_advice, this, true);
mRootLay = (RelativeLayout)mView.findViewById(R.id.layout_customview_writeqna_advice_rootLay);

 

mRootLay 레퍼런스변수에 이전에 Root였지만 현재는 Child가 된 RelativeLayout을 findViewById를 통하여 객체화 한다.
이제 마진을 아래와 같이 동적으로 변경해보자.
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)mRootLay.getLayoutParams();
mRightMarginDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, RIGHT_MARGIN_DP, getResources().getDisplayMetrics());
layoutParams.rightMargin = mRightMarginDp;
mRootLay.setLayoutParams(layoutParams);

 

우리가 동적으로 변경하려는 뷰인 RelativeLayout의 부모는 LinearLayout이기 때문에 LayoutParmas는 LinearLayout.LayoutParams로 받도록 한다.
그리고 마진을 동적 세팅해준 후 mRootLay.setLayoutParams()를 통하여 LayoutParams를 세팅해주면 동적으로 변하는 마진을 볼 수 있다.

 

꼭 기억해야 할 것은 XML 구조를 잡고 커스텀 뷰를 만들어서 동적으로 코드상에서 커스텀뷰를 생성해서 사용하는 상황에서, 동적으로 마진을 변경해야 하는 경우 최상위에 존재하는 Layout에는 동적으로 마진을 줄 수 없다는 것이다.
만약 그래야 하는 상황이라면 본문에서와 같이 마진을 변경해야 하는 Layout의 상위에 부모뷰를 하나 감싸게 하는 구조로 XML을 변경하여야 한다.

 

그렇게 구조를 약간만 변경한다면 쉽게 해결 될 수 있는 부분이다.
혹시 최상위 부모 레이아웃에 동적으로 마진이 적용되지 않아 고통받는 분들에게 약간이나마 도움이 되었으면 합니다.

 

Comments