라디오 버튼은 어떤 항목 내에서 하나만 선택하여 값을 받을 때 사용합니다.
우리가 흔히 익숙하게 알고 있는 동그란 모양의 그 버튼을 말합니다. 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
를 각각 다르게 지정해서 조회 버튼을 클릭했을 때 어떤 값이 출력되었는지를 확인해 볼 수 있습니다.
안드로이드에서는 RadioGroup
이라는 태그를 중심으로 하위에 RadioButton
이 위치하고 있으며 RadioGroup
은 html
의 라디오 버튼에서 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>
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")
}
}
}
}
}
체크박스는 라디오버튼과 다르게 체크가 되어 있는지를 확인한 후 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>
안드로이드의 체크박스는 <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!!"
}
}
}
}
}
}