Bucket Place/Android

[Android] Custom Radio Button / Multi-line Radio Button

Cloud Travel 2014. 12. 16. 15:06


  1. 들어가면서 



 오랜만입니다. 오랜만에 약간의 여유시간이 생겨서 이렇게 포스팅을 하게 되었습니다. 요즘 주된 작업이 안드로이드개발이라서 주제를 안드로이드로 잡았습니다. 특히, 오늘은 안드로이드의 기본 컴퍼넌트들 중의 하나인 라디오버튼을 커스텀 하는 방법을 알아보려고 합니다. 


 기본적으로 라디오 버튼을 커스텀하는 방법에 대해서 알아보고, 라디오 버튼을 묶어주는 라디오 그룹의 제한 사항을 알아보도록 하겠습니다..



  2. 커스텀 라디오 버튼(Radio button custom) 


 기본적으로 라디오 버튼을 생성하는 코드는 아래와 같습니다. 이는 체크박스에서도 그대로 적용이 가능합니다.

 <RadioButton 
        android:id="@+id/rb_option1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:text="option1" />

 기본적으로 생성된 라디오 버튼의 모습을 살펴보면 아래와 같습니다.

 

 

 이 버튼을 살펴보면 사람들이 무엇을 하고 싶어할까요?

 

 1) 글자 크기 및 색상을 변경하고 싶어 할 것입니다.

 2) 기본적으로는 아이콘을 없애고 싶어 할 것입니다.

 3) 더 나아가 아이콘을 변경하고 싶어 할 것입니다.

 1) 글자 변경은 TextView에서 적용되는 것을 그대로 적용시켜서 사용하면 되기 때문에 생략하겠습니다.

 2) 기본적으로 주어지는 아이콘을 어떻게 하면 없앨 수 있을 까요?

  - radio button과 check button 레이아웃 설정에서 android:button="@null"을 설정하면 아이콘이 사라집니다.

 3) 기본 아이콘 변경

  - radio button은 TextView를 상속받아서 사용하기 때문에 이를 이용해서 아이콘을 설정할 수 있습니다.

  - res/drawable 폴더를 생성해주고, radio 버튼을 xml을 하나 작성해줍니다. 

  res/drawable/radio.xml (아이콘은 직접 만들어 주시면 됩니다)

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">    
    <item android:state_checked="false" android:drawable="@drawable/ic_check_unchecked" />
    <item android:state_checked="true" android:drawable="@drawable/ic_check_checked" />
</selector>

 - check box나 radio button에서 drawable속성을 이용해서 원하는 위치에 아이콘을 추가하고, 

   drawablePadding을 이용하여 아이콘과 텍스트의 간격을 조정 시킵니다.

 - 커스텀한 라디오 버튼의 코드입니다. (라디오 버튼 클릭 효과를 보기 위해서 그룹으로 묶어주었습니다.)

    <RadioGroup 
        android:id="@+id/rg_line1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        
	    <RadioButton 
	        android:id="@+id/rb_option1"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content" 
	        android:padding="8dp"
	        android:button="@null"
	        android:drawableLeft="@drawable/radio"
	        android:drawablePadding="8dp"
	        android:text="option1" />
	    
	    <RadioButton 
	        android:id="@+id/rb_option2"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:padding="8dp"
	        android:layout_marginLeft="20dp" 
	        android:button="@null"
	        android:drawableLeft="@drawable/radio"
	        android:drawablePadding="8dp"
	        android:text="option2" />
    </RadioGroup>

 위 코드의 결과는 아래와 같습니다. 자주쓰는 라디오 버튼은 스타일로 지정하여서 관리하면 좋습니다.

 




 3. Multi-line radio button


 

 라디오 버튼을 커스텀하는데 성공을 하였습니다. 이제 열심이 라디오 버튼을 추가하는데 오류가 발생합니다. 그 오류는 바로 라디오버튼에 레이아웃을 잡는데 보통 발생합니다. 레이 아웃을 잡는데 RadioButton과 RadioGroup에는 하나의 제약사항이 있습니다.

 

 RadioButton의 부모는 RadioGroup여야 하는 것입니다. 

 예를 들어, 아래와 같은 레이아웃을 짠다고 생각해봅시다.

 

 

 option1~4까지는 하나의 라디오 그룹으로 묶여야 한다고하면, 일반적으로 사람들은 이렇게 생각합니다.

<RadioGroup 
        android:id="@+id/rg_line1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        
        <LinearLayout 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
        
		    <RadioButton 
		        android:id="@+id/rb_option1"
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content" 
		        android:padding="8dp"
		        android:button="@null"
		        android:drawableLeft="@drawable/radio"
		        android:drawablePadding="8dp"
		        android:text="option1" />
		    
		    <RadioButton 
		        android:id="@+id/rb_option2"
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content"
		        android:padding="8dp"
		        android:layout_marginLeft="20dp" 
		        android:button="@null"
		        android:drawableLeft="@drawable/radio"
		        android:drawablePadding="8dp"
		        android:text="option2" />
	    </LinearLayout>
	    
        <LinearLayout 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
        
		    <RadioButton 
		        android:id="@+id/rb_option3"
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content" 
		        android:padding="8dp"
		        android:button="@null"
		        android:drawableLeft="@drawable/radio"
		        android:drawablePadding="8dp"
		        android:text="option3" />
		    
		    <RadioButton 
		        android:id="@+id/rb_option4"
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content"
		        android:padding="8dp"
		        android:layout_marginLeft="20dp" 
		        android:button="@null"
		        android:drawableLeft="@drawable/radio"
		        android:drawablePadding="8dp"
		        android:text="option4" />
	    </LinearLayout>
    </RadioGroup>

 하지만 이렇게 작성해본 경험이 있다면 알겠지만 이 것은 매우 큰 오류를 유발합니다. 

 


 아까의 원칙에 의해서 라디오 버튼이 오류가 나서 자신의 역할을 하지 못한다는 것이죠.  

 원칙에 의거해서 소스 코드를 수정하면 아래와 같이 될 것입니다.


<LinearLayout 
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
        android:orientation="vertical">

        <RadioGroup 
	        android:id="@+id/rg_line1"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:orientation="horizontal">
		    
		    <RadioButton 
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content" 
		        android:padding="8dp"
		        android:button="@null"
		        android:drawableLeft="@drawable/radio"
		        android:drawablePadding="8dp"
		        android:text="option1" />
		    
		    <RadioButton 
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content"
		        android:padding="8dp"
		        android:layout_marginLeft="20dp" 
		        android:button="@null"
		        android:drawableLeft="@drawable/radio"
		        android:drawablePadding="8dp"
		        android:text="option2" />
   		</RadioGroup>
  
		<RadioGroup 
	        android:id="@+id/rg_line2"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:orientation="horizontal">
		    <RadioButton 
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content" 
		        android:padding="8dp"
		        android:button="@null"
		        android:drawableLeft="@drawable/radio"
		        android:drawablePadding="8dp"
		        android:text="option3" />
		    
		    <RadioButton 
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content"
		        android:padding="8dp"
		        android:layout_marginLeft="20dp" 
		        android:button="@null"
		        android:drawableLeft="@drawable/radio"
		        android:drawablePadding="8dp"
		        android:text="option4" />
	   	</RadioGroup>
  	</LinearLayout>

 이렇게 해주면 아래와 같은 일이 발생합니다. 각 한줄마다 하나의 채크가 생긴다는 것이죠~

 

 이 것에 대한 처리를 소스코드에서 해줘야 한답니다~

 라디오 버튼마다 리스너를 달아서 처리를 해주면 됩니다. 아래의 코드를 참조해주세요.

public class MainActivity extends Activity implements OnClickListener {

	private RadioGroup mRgLine1;
	private RadioGroup mRgLine2;
	
	private Button mBtnConfirm;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        mRgLine1 = (RadioGroup) findViewById(R.id.rg_line1);
        mRgLine1.clearCheck();
        mRgLine1.setOnCheckedChangeListener(listener1);
        mRgLine2 = (RadioGroup) findViewById(R.id.rg_line2);
        mRgLine2.clearCheck();
        mRgLine2.setOnCheckedChangeListener(listener2);
        
        mBtnConfirm = (Button) findViewById(R.id.btn_id_confirm);
        mBtnConfirm.setOnClickListener(this);
    }
    
    private OnCheckedChangeListener listener1 = new OnCheckedChangeListener() {

		@Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            if (checkedId != -1) {
            	mRgLine2.setOnCheckedChangeListener(null); 
                mRgLine2.clearCheck(); 
                mRgLine2.setOnCheckedChangeListener(listener2);
            }
        }
    };

    private OnCheckedChangeListener listener2 = new OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            if (checkedId != -1) {
            	mRgLine1.setOnCheckedChangeListener(null); 
                mRgLine1.clearCheck(); 
                mRgLine1.setOnCheckedChangeListener(listener1);
            }
        }
    };

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch(v.getId()){
		case R.id.btn_id_confirm:
			String selectedResult ="";
			if ( mRgLine1.getCheckedRadioButtonId() > 0 ){
				View radioButton = mRgLine1.findViewById(mRgLine1.getCheckedRadioButtonId());
				int radioId = mRgLine1.indexOfChild(radioButton);
				RadioButton btn = (RadioButton) mRgLine1.getChildAt(radioId);
				selectedResult = (String) btn.getText();
			} else if ( mRgLine2.getCheckedRadioButtonId() > 0 ){
				View radioButton = mRgLine2.findViewById(mRgLine2.getCheckedRadioButtonId());
				int radioId = mRgLine2.indexOfChild(radioButton);
				RadioButton btn = (RadioButton) mRgLine2.getChildAt(radioId);
				selectedResult = (String) btn.getText();
			} 
			
			Toast.makeText(getApplicationContext(), selectedResult, Toast.LENGTH_SHORT).show();
			break;
		}
	}
}

 아래의 프로젝트 첨부파일을 올립니다.



blog.zip




 4. End



오랜만에 글을 써서 약간의 귀찮음에 의해서 마지막 멀티라인을 컨트롤하는 부분은 설명이 적습니다..;

 양해바라며, 질문 사항은 댓글로 남겨주시면 확인과 동시에 답글을 남겨드리겠습니다~^^