[안드로이드 스튜디오 코틀린] 약관 동의 (전체, 필수, 선택) 예제
앱에서 회원가입을 할 때, 이용 약관 CheckBox를 많이 볼 수 있다.
사실 예전부터 이용 약관에서 계속 막히고.. 잘 안되고... 뜻대로 수행되지 않아서 계속 해맸었다..!
그러다가, 마침내 성공하게 되어 드디어 이용약관 예제 글을 쓰게 되었다.
(나처럼 ... 헤매던 사람들에게 한 줄기의 빛이 되길.. 바라며... !.. 다들 화이팅입니다)
우선, 전체 동의를 하는 CheckBox가 존재해야 하고, 필수 동의와, 선택 동의 3가지가 전부 있는 이용 약관을 만들어 보려고 한다.
먼저 체크 전, 후 vector를 생성해준다
- drawable -> New -> Vector Asset
그리고 이 둘을 체크 / 비체크 상태로 만들어줄 drawable을 생성해줍니다.
- drawable -> New -> Drawable Resource File
이렇게 하고
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/baseline_check_circle"/>
<item android:state_checked="false" android:drawable="@drawable/baseline_check_circle_outline"/>
</selector>
true일 때 안에가 색칠되게 만들어주었습니다.
그리고 다음 화면으로 넘어갈 Button도 아래처럼 만들어줍니다.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true" android:drawable="@drawable/rect_stroke_skyblue"/>
<item android:state_enabled="false" android:drawable="@drawable/rect_stroke_gray"/>
</selector>
다음 전체적인 이용약관 UI를 구성해줍니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/mainTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:text="이용 약관"
android:textSize="32sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/allCheckLL"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_marginTop="50dp"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/mainTV">
<CheckBox
android:id="@+id/allCheckBox"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_gravity="center"
android:layout_marginTop="1dp"
android:background="@drawable/custom_checkbox_background"
android:button="@null"
android:clickable="false" />
<TextView
android:id="@+id/allCheckTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="4dp"
android:text="이용 약관 전체 "
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/allAgreeTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="동의"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="@+id/firstCheckLL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="45dp"
android:layout_marginTop="35dp"
android:layout_marginEnd="30dp"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/allCheckLL">
<CheckBox
android:id="@+id/firstCheckBox"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center"
android:background="@drawable/custom_checkbox_background"
android:button="@null"
android:clickable="false" />
<TextView
android:id="@+id/firstCheckTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="4dp"
android:text="@string/personInfoAgree"
android:textSize="14sp" />
<TextView
android:id="@+id/firstAgreeTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="4dp"
android:text="동의"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/secondCheckLL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="45dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="30dp"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/firstCheckLL">
<CheckBox
android:id="@+id/secondCheckBox"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center"
android:background="@drawable/custom_checkbox_background"
android:button="@null"
android:clickable="false" />
<TextView
android:id="@+id/secondCheckTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="4dp"
android:text="@string/serviceUseAgree"
android:textSize="14sp" />
<TextView
android:id="@+id/secondAgreeTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="4dp"
android:text="동의"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/threeCheckLL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="45dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="30dp"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/secondCheckLL">
<CheckBox
android:id="@+id/threeCheckBox"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center"
android:background="@drawable/custom_checkbox_background"
android:button="@null"
android:clickable="false" />
<TextView
android:id="@+id/threeCheckTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="4dp"
android:text="@string/locationInfoAgree"
android:textSize="14sp" />
<TextView
android:id="@+id/threeAgreeTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="4dp"
android:text="동의"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/fourCheckLL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="45dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="30dp"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/threeCheckLL">
<CheckBox
android:id="@+id/fourCheckBox"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center"
android:background="@drawable/custom_checkbox_background"
android:button="@null"
android:clickable="false" />
<TextView
android:id="@+id/fourCheckTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="4dp"
android:text="@string/advertiseInfoAgree"
android:textSize="14sp" />
<TextView
android:id="@+id/fourAgreeTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="4dp"
android:text="동의"
android:textSize="14sp" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/nextButton"
android:layout_width="300dp"
android:layout_height="80dp"
android:layout_marginBottom="40dp"
android:background="@drawable/custom_button_background"
android:clickable="true"
android:enabled="false"
android:focusable="true"
android:paddingEnd="5dp"
android:paddingBottom="4dp"
android:text="다음"
android:textColor="@color/white"
android:textSize="17sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
저는 LinearLayout 클릭시, CheckBox의 상태를 바꾸고 싶어 LinearLayout에 Clickable을 true로 넣어주고, CheckBox에는 false를 주어 전체적인 선택을 하는 방안으로 해주었습니다.
메인 코드는
package com.example.checkboxexam
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.example.checkboxexam.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var isAllSelected = false
private var isFirstSelected = false
private var isSecondSelected = false
private var isThreeSelected = false
private var isFourSelected = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
checkClickState()
}
private fun checkClickState() {
// 전체 동의 LinearLayout 클릭 시 checkbox가 check되는 클릭 리스너 설정
binding.allCheckLL.setOnClickListener {
val isChecked = !binding.allCheckBox.isChecked
binding.allCheckBox.isChecked = isChecked
binding.firstCheckBox.isChecked = isChecked
binding.secondCheckBox.isChecked = isChecked
binding.threeCheckBox.isChecked = isChecked
binding.fourCheckBox.isChecked = isChecked
binding.nextButton.isEnabled = isChecked
isAllSelected = isChecked
isFirstSelected = isChecked
isSecondSelected = isChecked
isThreeSelected = isChecked
isFourSelected = isChecked
allCheckState()
firstCheckState()
secondCheckState()
threeCheckState()
fourCheckState()
}
binding.firstCheckLL.setOnClickListener {
binding.firstCheckBox.isChecked = !binding.firstCheckBox.isChecked
isFirstSelected = binding.firstCheckBox.isChecked
firstCheckState()
updateButtonState()
}
binding.secondCheckLL.setOnClickListener {
binding.secondCheckBox.isChecked = !binding.secondCheckBox.isChecked
isSecondSelected = binding.secondCheckBox.isChecked
secondCheckState()
updateButtonState()
}
binding.threeCheckLL.setOnClickListener {
binding.threeCheckBox.isChecked = !binding.threeCheckBox.isChecked
isThreeSelected = binding.threeCheckBox.isChecked
threeCheckState()
updateButtonState()
}
binding.fourCheckLL.setOnClickListener {
binding.fourCheckBox.isChecked = !binding.fourCheckBox.isChecked
isFourSelected = binding.fourCheckBox.isChecked
fourCheckState()
updateButtonState()
}
}
private fun updateButtonState() {
val mushSelected = isFirstSelected && isSecondSelected && isThreeSelected
if (mushSelected) {
binding.nextButton.isEnabled = true
}
val fourSelected = isFirstSelected && isSecondSelected && isThreeSelected && isFourSelected
if (fourSelected) {
binding.allCheckBox.isChecked = isFourSelected
allCheckState()
binding.nextButton.isEnabled = isFourSelected
} else if (mushSelected) {
// 필수 동의만 선택되었을 때
binding.allCheckBox.isChecked = false
allCheckState()
}
}
private fun allCheckState() {
if (binding.allCheckBox.isChecked) {
enabledAgreeText(binding.allCheckTV, binding.allAgreeTV)
} else {
disEnabledAgreeText(binding.allCheckTV, binding.allAgreeTV)
}
}
private fun firstCheckState() {
if (binding.firstCheckBox.isChecked) {
enabledAgreeText(binding.firstCheckTV, binding.firstAgreeTV)
} else {
disEnabledAgreeText(binding.firstCheckTV, binding.firstAgreeTV)
}
}
private fun secondCheckState() {
if (binding.secondCheckBox.isChecked) {
enabledAgreeText(binding.secondCheckTV, binding.secondAgreeTV)
} else {
disEnabledAgreeText(binding.secondCheckTV, binding.secondAgreeTV)
}
}
private fun threeCheckState() {
if (binding.threeCheckBox.isChecked ) {
enabledAgreeText(binding.threeCheckTV, binding.threeAgreeTV)
} else {
disEnabledAgreeText(binding.threeCheckTV, binding.threeAgreeTV)
}
}
private fun fourCheckState() {
if (binding.fourCheckBox.isChecked) {
enabledAgreeText(binding.fourCheckTV, binding.fourAgreeTV)
} else {
disEnabledAgreeText(binding.fourCheckTV, binding.fourAgreeTV)
}
}
private fun enabledAgreeText(textView: TextView, agreeText: TextView) {
textView.setTextColor(ContextCompat.getColor(this, R.color.skyblue))
agreeText.setTextColor(ContextCompat.getColor(this, R.color.skyblue))
}
private fun disEnabledAgreeText(textView: TextView, agreeText: TextView) {
textView.setTextColor(ContextCompat.getColor(this, R.color.black))
agreeText.setTextColor(ContextCompat.getColor(this, R.color.black))
}
}
updateButtonState()함수에서 필수 동의를 다 체크 했을 때 버튼을 활성화해주고, 4개의 동의를 다 해주면 버튼을 활성화 해주었는데 여기서 선택 동의를 해제할 시 버튼은 다시 false처리를 하도록 구현하였습니다.
구현 화면
선택 전 -> 전체 동의 -> 필수 동의
총 코드
https://github.com/songmik/CheckBoxExam