본문 바로가기

Study/Android

Android : 라디오버튼과 체크박스

HTML과 Android의 라디오 버튼 비교


HTML의 라디오 버튼

라디오 버튼은 어떤 항목 내에서 하나만 선택하여 값을 받을 때 사용합니다.

우리가 흔히 익숙하게 알고 있는 동그란 모양의 그 버튼을 말합니다. html에서는 다음과 같은 방법으로 만들어주었습니다.

<input type="radio" />

이 때, 다양한 선택지가 존재한다면 name 속성으로 라디오 버튼을 그룹화 해주고 각각의 value를 다르게 지정해서 선택한 값을 서버로 전송해 줄 수 있는 것입니다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Fruits</title>
  </head>
  <body>
    <form method="get">
      <input type="radio" name="fruit" value="apple" /> 사과 <br />
      <input type="radio" name="fruit" value="pear" /> 배 <br />
      <input type="radio" name="fruit" value="grape" /> 포도 <br />
      <button type="button" onclick="onSubmit()">조회</button>
    </form>
  </body>

  <script>
    function onSubmit() {
      let clickedBtn = document.querySelector('input[name="fruit"]:checked')
        .value;
      console.log(clickedBtn);
    }
  </script>
</html>

위의 코드에서 살펴보면 각각의 라디오 버튼은 name="fruit"이라는 속성으로 그룹화 되어있기 때문에 셋 중에 하나가 선택되는 구조로 되어 있음을 알 수 있습니다. 이 때 value를 각각 다르게 지정해서 조회 버튼을 클릭했을 때 어떤 값이 출력되었는지를 확인해 볼 수 있습니다.

Android에서의 라디오 버튼

안드로이드에서는 RadioGroup이라는 태그를 중심으로 하위에 RadioButton이 위치하고 있으며 RadioGrouphtml의 라디오 버튼에서 name과 같은 역할을 합니다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">


    <RadioGroup
            android:id="@+id/radioGroup"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
    >
        <RadioButton
                android:id="@+id/radio1"
                android:text="사과"
                android:checked="true"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
        />
        <RadioButton
                android:id="@+id/radio2"
                android:text="바나나"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
        />
        <RadioButton
                android:id="@+id/radio3"
                android:text="오렌지"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
        />
    </RadioGroup>

</androidx.constraintlayout.widget.ConstraintLayout>

라디오 그룹을 먼저 봤을 때 보통의 태그들과 별반 다를 것은 없어보입니다.
아이디가 주어져있고, 컨텐츠의 너비, 높이 그리고 기준점이 등록되어 있습니다.

그렇다면 라디오 버튼 하나만 가져와서 분해 해보겠습니다.

<RadioButton
    android:id="@+id/radio3"
    android:text="오렌지"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
/>

안드로이드와 html의 라디오 버튼 접근 방식의 차이라고 한다면 html에서는 라디오버튼의 값을 조회할 때 value로 어떤 값이 선택되었는지 확인할 수 있지만, 안드로이드에서는 id를 사용해서 해당 아이디의 버튼이 선택되었을 경우에 대한 작업을 처리하게 할 수 있습니다.

예를 들어서 radio1이라는 아이디를 가진 버튼이 클릭되었을 때 작업을 처리한다면 R.id.radio1 -> 처리할 작업과 같은 형태로 작성할 수 있습니다.


선택된 라디오 버튼 값 조회해보기


준비사항

라디오 버튼 그룹 밑에서 바로 확인할 수 있도록 텍스트뷰를 만들어서 값을 뿌려줄 준비를 해보겠습니다.

레이아웃 XML에서 텍스트뷰를 추가해줍니다. 이 때 <TextView>의 아이디는 textView로 줍니다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">


    <RadioGroup
            android:id="@+id/radioGroup"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
    >
        <RadioButton
                android:id="@+id/radio1"
                android:text="사과"
                android:checked="true"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
        />
        <RadioButton
                android:id="@+id/radio2"
                android:text="바나나"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
        />
        <RadioButton
                android:id="@+id/radio3"
                android:text="오렌지"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
        />
    </RadioGroup>
    <TextView
            android:id="@+id/textView"
            android:text="TextView"
            android:layout_width="226dp"
            android:layout_height="60dp"
            app:layout_constraintTop_toBottomOf="@+id/radioGroup"
            android:layout_marginTop="60dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintVertical_bias="0.0"
    />
</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity에서 코드 작성

by lazy를 사용해서 컴포넌트에 접근하기

app 디렉터리 안에 들어있는 build.gradle에 뷰를 객체화 해주기 위해 다음과 같이 추가해줍니다.

android {
...

    buildFeatures {
        viewBinding true
    }
}

그 다음 상단의 Sync Now를 클릭하여 프로젝트를 업데이트 해줍니다.

다시 MainActivity로 돌아와서

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.RadioGroup
import android.widget.TextView
import com.example.sample11.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    // 컴포넌트에 자유롭게 접근 가능
    val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {

        // ActivityMainBiding을 사용할 때 setContentView를 아래와 같이 사용한다.
        setContentView(binding.root)

        // 실시간으로 바뀌는 값 가져오기
        binding.radioGroup.setOnCheckedChangeListener { _, checkedId ->
            Log.d(" ", "RadioButton is Clicked")
            when (checkedId) {
                R.id.radio1 -> {
                    binding.textView.text = "Apple is selected"
                    Log.d(" ", "Apple is selected")
                }
                R.id.radio2 -> {
                    binding.textView.text = "Banana is selected"
                    Log.d(" ", "Banana is selected")
                }
                R.id.radio3 -> {
                    binding.textView.text = "Orange is selected"
                    Log.d(" ", "Orange is selected")
                }
            }
        }

        super.onCreate(savedInstanceState)
    }
}

여기에서는 by lazy를 사용해서 컴포넌트에 보다 쉽게 접근하여 setOnCheckedChangeListener를 사용해서 각 라디오버튼의 아이디를 기준으로 특정 작업을 처리하도록 해주었습니다.

아이디 값으로 바로 컴포넌트에 접근하는 방법

by lazy로 접근하는 방법은 접근해야 할 컴포넌트의 개수가 많을 때 유리하게 사용할 수 있습니다.

우리가 접근할 컴포넌트는 두개에 한정되기 때문에 어떤 방법을 사용하더라도 크게 문제가 되진 않지만 접근해야 할 컴포넌트의 개수가 많다면 아래와 같이 id 값으로 바로 접근하는 것은 코드의 양이 많아지는 결과를 초래할 수 있씁니다.

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.RadioGroup
import android.widget.TextView

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {

        setContentView(R.layout.activity_main)
        super.onCreate(savedInstanceState)

        // id로 접근하기
        val radioGroup = findViewById<RadioGroup>(R.id.radioGroup)
        val textView = findViewById<TextView>(R.id.textView)

        radioGroup.setOnCheckedChangeListener { _, checkedId ->
            Log.d(" ", "RadioButton is Clicked")
            when (checkedId) {
                R.id.radio1 -> {
                    textView.text = "Apple is selected"
                    Log.d(" ", "Apple is selected")
                }
                R.id.radio2 -> {
                    textView.text = "Banana is selected"
                    Log.d(" ", "Banana is selected")
                }
                R.id.radio3 -> {
                    textView.text = "Orange is selected"
                    Log.d(" ", "Orange is selected")
                }
            }
        }
    }
}

HTML과 Android의 체크 박스 비교


HTML의 체크박스

체크박스는 라디오버튼과 다르게 체크가 되어 있는지를 확인한 후 Boolean으로 값을 반환해줍니다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Fruits</title>
  </head>
  <body>
    <form method="get">
      <input type="checkbox" name="fruit" value="apple" /> 사과 <br />
      <input type="checkbox" name="fruit" value="pear" /> 배 <br />
      <input type="checkbox" name="fruit" value="grape" /> 포도 <br />
      <button type="button" onclick="onSubmit()">조회</button>
    </form>
  </body>

  <script>
    function onSubmit() {
      let checkbox = document.querySelector("input:checked");
      console.log(Boolean(checkbox));
    }
  </script>
</html>

Android의 체크박스

안드로이드의 체크박스는 <ChechBox>라는 태그를 사용하여 만들어줍니다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    <CheckBox
            android:id="@+id/checkBox"
            android:text="CheckBox"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintBottom_toTopOf="@+id/textView"
            android:layout_marginBottom="148dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="1.0"/>
    <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.596"/>
</androidx.constraintlayout.widget.ConstraintLayout>

이 체크박스를 체크여부에 따라 텍스트뷰의 내용을 바꿔보겠습니다.

우선 MainActivity에서 뷰를 객체화 해주기 위해 build.gradle에 다음과 같이 추가해줍니다.

android {
...

    buildFeatures {
        viewBinding true
    }
}

MainActivity에서 각 컴포넌트에 접근해서 체크박스가 체크되었을 때, 그렇지 않을 때 텍스트뷰의 내용을 바꿔주도록 하겠습니다.

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.CheckBox
import android.widget.CompoundButton
import android.widget.TextView

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // traditional
        setContentView(R.layout.activity_main)
        val checkBox = findViewById<CheckBox>(R.id.checkBox)
        val textView = findViewById<TextView>(R.id.textView)

        checkBox.setOnCheckedChangeListener { _, isChecked ->
            if (isChecked) {
                textView.text = "checked!!"
            } else {
                textView.text = "unChecked!!"
            }
        }
    }
}

ActivityMainBinding을 사용하는 방법으로 작성해보겠습니다. 이 때 CompoundButton을 사용하여 모든 버튼 요소에 접근에 접근해서 OnCheckedChangeListener를 사용하여 체크박스의 상태가 바뀔 때마다 텍스트뷰의 내용을 바꿔주는 함수를 별도로 작성해주겠습니다.

이를 setOnCheckedChangeListener의 매개변수로 받아서 체크박스에 대한 이벤트를 처리해줍니다.

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.CheckBox
import android.widget.CompoundButton
import android.widget.TextView
import com.example.sample12.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(binding.root)
        binding.checkBox.setOnCheckedChangeListener(checkListener)

    }

    val checkListener by lazy {
        // CompoundButton으로 모든 버튼 요소에 접근 가능
        CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
            val checkBox = findViewById<CheckBox>(R.id.checkBox)
            val textView = findViewById<TextView>(R.id.textView)

            if (isChecked) {
                when (buttonView.id) {
                    R.id.checkBox -> {
                        textView.text = "checked!!"
                    }
                }
            } else {
                when (buttonView.id) {
                    R.id.checkBox -> {
                        textView.text = "unChecked!!"
                    }
                }
            }
        }
    }
}

'Study > Android' 카테고리의 다른 글

Android : 배경에 이미지 넣기  (0) 2022.02.16
Android : 컨텍스트 메뉴와 스피너  (0) 2022.02.16
Android : 상단메뉴와 이벤트 처리  (0) 2022.02.16
Android : Layout  (0) 2022.02.16
Android : 메인 화면 구성  (0) 2022.02.16