박상권의 삽질블로그

[안드로이드/Android]CustomView를 만들어서 재사용하기 본문

IT/Android-TIP (한글)

[안드로이드/Android]CustomView를 만들어서 재사용하기

박상권 2015. 11. 2. 21:45

제가 운영하고 있는 유튜브 채널 '개발자 테드박'에도 많은 관심 부탁드려요.
스타트업/개발자/IT 관련된 여러 영상을 올리고 있습니다.
영상보러가기



블로그를 Medium으로 옮겨서 운영하고 있습니다.
앞으로 새로운 글은 모두 미디엄 블로그를 통해서 올릴 예정입니다.
미디엄에서 다양하고 유익한 포스팅을 살펴보세요
미디엄 블로그 보기




이전 포스팅에서 Style테마를 이용하여 일정한 레이아웃의 속성을 만들고 이를 재사용하는 방법에 대해서 알아 보았습니다.

[안드로이드]style테마 활용으로 노가다코딩 줄이는 방법




이 방법보다 좀더 심화된 방식인 Custom View를 만드는 방법에 대해서 포스팅 해보겠습니다.



먼저 아래 사진을 예로 들어보겠습니다.

로그인버튼이 각각 3개씩 있는 레이아웃입니다.






잘 보면 3개의 버튼이 레이아웃 구성이 똑같은걸 알 수 있습니다.

기본적인 로그인보튼의 형태는 같지만 아이콘, 텍스트, 배경색상, 텍스트 색상등은 서로 다른것을 확인할 수 있습니다.



각각의 버튼 layout은 아래와 같을 것입니다.



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/bg"
android:layout_width="match_parent"
android:layout_height="55dp"
android:background="@drawable/login_kakao_bg"
android:gravity="center"
android:padding="10dp">
<!-- android:background="@drawable/kakao_login_button_background" -->


<ImageView
android:id="@+id/symbol"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="20dp"
android:src="@drawable/login_kakao_symbol"

/>


<TextView
android:id="@+id/text"
style="@style/CustomText_Subhead"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="카카오톡 로그인"
android:textColor="@color/kakao_brown"
android:textStyle="bold" />

</LinearLayout>







위의 화면처럼 버튼이 3개라면 저 레이아웃 소스코드를 3번 복사/붙여넣기 해서 장문의 레이아웃을 만들겠죠...

만약에 버튼이 10개라면? 100개라면??



그러다가 padding값을 10dp에서 16dp로 바꾸고싶다면??

상상만 해도 끔찍합니다.(복사 붙여넣기보다 더 무서운게 그것들을 전부다 한땀한땀 수정하는 작업이겠죠...)




이러한 경우는 앞서배운 style테마를 이용하는것보다 CustomView를 만들어서 이를 재사용하는것이 좋습니다.





우리는 로그인버튼의 레이아웃형태는 그대로 유지하고 아이콘과 텍스트만 변경하고 싶습니다.

결론적으로 만들어진 CustomView를 사용하면 아래와 같이 사용할 수 있습니다.







우선 미리 완성된 CustomView의 사용예제를 살펴보겠습니다.


<kr.co.selphone.welcome.login.CustomLoginButton
android:id="@+id/login_kakao"
style="@style/LoginButtonStyle"
app:bg="@drawable/login_kakao_bg"
app:symbol="@drawable/login_kakao_symbol"
app:text="카카오톡"
app:textColor="@color/kakao_brown"

/>


custom하게 만든 속성을 이용해서 배경색, 아이콘 이미지, 텍스트, 텍스트 색상 등을 지정할 수 있습니다.









위의 3개의 서로다른 로그인버튼을 만들고자 하는경우는 아래와 같이 사용해 주면 됩니다.



<kr.co.selphone.welcome.login.CustomLoginButton
android:id="@+id/login_kakao"
style="@style/LoginButtonStyle"
app:bg="@drawable/login_kakao_bg"
app:symbol="@drawable/login_kakao_symbol"
app:text="카카오톡"
app:textColor="@color/kakao_brown"
/>

<kr.co.selphone.welcome.login.CustomLoginButton
android:id="@+id/login_naver"
style="@style/LoginButtonStyle"
app:bg="@drawable/login_naver_bg"
app:symbol="@drawable/login_naver_symbol"
  app:text="네이버"
app:textColor="@color/white"
/>

<kr.co.selphone.welcome.login.CustomLoginButton
android:id="@+id/login_google"
style="@style/LoginButtonStyle"
app:bg="@drawable/login_google_bg"
app:symbol="@drawable/login_google_symbol"
app:text="구글"
app:textColor="@color/google_red"
/>




복잡한 레이아웃 구성도 하나의 CustomView로 만들어준뒤 해당 CustomView를 재사용하면 편리하고 유용하게 화면을 구성할 수 있습니다.






CustomView 만들기






1. layout xml파일 생성


CustomView의 기본으로 쓰일 layout xml파일을 만들어 줍니다.












2. attrs.xml 설정


custom하게 만들어줄 attribute를 설정해줍니다.

value -> attrs.xml 파일에 아래 내용을 추가해줍니다.(만약 해당 파일이 없다면 만드시면 됩니다.)


<declare-styleable name="LoginButton">
<attr name="bg" format="reference|integer" />
<attr name="symbol" format="reference|integer" />
<attr name="text" format="reference|string" />
<attr name="textColor" format="reference|integer" />
</declare-styleable>



이 attr 속성을 보았을때 4가지를 속성값으로 받아서 적용할 수 있게 할것입니다.


    <attr name="text" format="reference|string" /> 

이 attr은 나중에 app:text="....." 로 쓰일수 있으며 '가나다라' 같은 직접적인 String과 @string/aaaa 같은 reference를 넣어줄 수 있습니다.












3. CustomView 만들기


(클래스 전체 소스는 아래에 있습니다)




1) CustomView의 생성자에서 initView, getAttrs 함수를 사용합니다



public CustomLoginButton(Context context) {
super(context);
initView();

}

public CustomLoginButton(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
getAttrs(attrs);

}

public CustomLoginButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
initView();
getAttrs(attrs, defStyle);

}




2) initView()에서는 미리 만들어둔 xml 파일을 할당해주고 각각의 View를 설정해줍니다.



private void initView() {

String infService = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater li = (LayoutInflater) getContext().getSystemService(infService);
View v = li.inflate(R.layout.welcome_login_button, this, false);
addView(v);

bg = (LinearLayout) findViewById(R.id.bg);
symbol = (ImageView) findViewById(R.id.symbol);

text = (TextView) findViewById(R.id.text);

}











3) getAttrs() 및 setTypeArray()함수에서는 우리가 attrs.xml 에 선언해둔 attribute를 이용하여 이를 각각의 View에 설정해주는 작업을 합니다.




private void getAttrs(AttributeSet attrs) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.LoginButton);

setTypeArray(typedArray);
}


private void getAttrs(AttributeSet attrs, int defStyle) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.LoginButton, defStyle, 0);
setTypeArray(typedArray);

}


private void setTypeArray(TypedArray typedArray) {


int bg_resID = typedArray.getResourceId(R.styleable.LoginButton_bg, R.drawable.login_naver_bg);
bg.setBackgroundResource(bg_resID);

int symbol_resID = typedArray.getResourceId(R.styleable.LoginButton_symbol, R.drawable.login_naver_symbol);
symbol.setImageResource(symbol_resID);

int textColor = typedArray.getColor(R.styleable.LoginButton_textColor, 0);
text.setTextColor(textColor);

String text_string = typedArray.getString(R.styleable.LoginButton_text);
text.setText(text_string);


typedArray.recycle();

}



아래는 CustomLoginButton의 전체 소스코드 입니다















이렇게 완성된 CustomView를 사용하고자하는 xml에서 아래와 같이 재사용해주면 됩니다.

물론 여러번 재사용할때도 CustomView을 사용하고 각각 bg,symbol,text,textColor에 맞는 값을 넣어주시면 됩니다.


<kr.co.selphone.welcome.login.CustomLoginButton
android:id="@+id/login_kakao"
style="@style/LoginButtonStyle"
app:bg="@drawable/login_kakao_bg"
app:symbol="@drawable/login_kakao_symbol"

app:text="카카오톡"
app:textColor="@color/kakao_brown"

/>








위의 예재대로 그대로 따라해보시고 CustomView를 만드는 원리에 대해서 이해하셨다면 충분히 이를 응용해서 원하시는 CustomView를 만드실 수 있을겁니다.

이상 CustomView를 만들어서 재사용하는 방법에 대해 소개 해드렸습니다.

감사합니다.

6 Comments
  • BlogIcon 몽국 2015.11.03 09:27 신고 안녕하세요. 저도 안드로이드 블로그를 시작하려고 하는데 궁금한게 생겨 글남겨요~!
    지금 포스팅에 소스코드같은경우 어덯게 넣으신건지 궁금해요~스튜디오 포맷이 그대로 들어왔는데..
    공유해주실 수 있을까요?
  • BlogIcon 박상권 2015.11.05 20:11 신고 스튜디오에 있는 소스코드를 그대로 긁어오면 자동으로 html 포맷이 적용되는것 같아요~
    그냥 ctrl_+ c,v 해보세요~
  • BlogIcon yeojoy 2016.12.07 21:03 신고 String infService = Context.LAYOUT_INFLATER_SERVICE;
    LayoutInflater li = (LayoutInflater) getContext().getSystemService(infService);
    View v = li.inflate(R.layout.welcome_login_button, this, false);
    addView(v);

    이 부분에서 inflate 하고 addView를 하면 LinearLayout 안에 다시 LinearLayout을 하는 것으로 보이는대요
    바로 inflate 시킬 수 있습니다.

    저 코드를 바꿔 보면
    inflate(getContext(), R.layout.welcome_login_button, this);
    이렇게 깔끔하게 한줄로 끝낼 수 있습니다.

    글 잘 보고 있습니다. '-'b
  • BlogIcon 박상권 2016.12.14 14:14 신고 오~ yeojoy님, 좋은정보 감사합니다!
  • BlogIcon 피아트룩스 2017.05.24 18:16 신고 CustomText_Subhead style 좀 알 수 있을까요?
  • BlogIcon 망나니개발자 2018.05.30 23:09 신고 안녕하세요? Databinding 등 좋은 자료들 참고해서 열심히 공부하고 있는데 CustomView를 제작한 후 다른 컴포넌트 ex) Recycler View와 같이 활용할려고 할 때 다음과 같은 에러가 뜨는데 혹시 이유 아시나요!?

    Caused by: java.lang.ArrayIndexOutOfBoundsException: length=3; index=3
    at android.databinding.ViewDataBinding.mapBindings(ViewDataBinding.java:1171)
    at android.databinding.ViewDataBinding.mapBindings(ViewDataBinding.java:1228)
    at android.databinding.ViewDataBinding.mapBindings(ViewDataBinding.java:1228)
    at android.databinding.ViewDataBinding.mapBindings(ViewDataBinding.java:1228)
    at android.databinding.ViewDataBinding.mapBindings(ViewDataBinding.java:1228)
    at android.databinding.ViewDataBinding.mapBindings(ViewDataBinding.java:679)
    at com.rorrim.mang.smartmirror.databinding.ActivityMusicBinding.<init>(ActivityMusicBinding.java:35)
    at android.databinding.DataBinderMapperImpl.getDataBinder(DataBinderMapperImpl.java:51)
    at android.databinding.DataBindingUtil.bind(DataBindingUtil.java:199)
    at android.databinding.DataBindingUtil.bindToAddedViews(DataBindingUtil.java:327)
    at android.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:306)
    at android.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:284)
    at com.rorrim.mang.smartmirror.Activity.MusicActivity.onCreate(MusicActivity.java:33)
    at android.app.Activity.performCreate(Activity.java:7174)
댓글쓰기 폼