관리 메뉴

나만을 위한 블로그

[Android] RxBinding으로 체크박스 체크 상태 관리하기 본문

Android

[Android] RxBinding으로 체크박스 체크 상태 관리하기

참깨빵위에참깨빵 2022. 5. 23. 22:08
728x90
반응형

체크박스의 체크 상태를 확인해서 버튼을 활성화하는 등의 처리는 자바/코틀린 기본 문법으로도 충분하다.

하지만 RxBinding을 쓰면 좀 더 간결한 코드로 체크박스의 체크 상태에 따라 버튼을 활성화시킬 수 있다.

여기 쓰인 코드가 절대 정답은 아니고 RxBinding으로 이런 로직을 짤 수도 있다는 걸 남기는 것이니 이 코드는 참고만 하자. 오히려 아래 코드는 리팩토링할 여지가 많은 코드다.

 

먼저 의존성을 프로젝트에 넣어준다. 체크박스는 RxBinding2 버전에서만 작동하기 때문에 이 버전보다 높은 버전을 사용할 경우 체크박스에 RxBinding을 사용할 수 없으니 주의하자.

 

implementation 'com.jakewharton.rxbinding2:rxbinding:2.2.0'

 

그 다음 체크박스 5개와 버튼 하나가 있는 간단한 화면을 만든다.

 

<?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=".rxbinding.RxBindingActivity">

    <CheckBox
        android:id="@+id/first_checkbox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:text="1번 체크박스"/>

    <CheckBox
        android:id="@+id/second_checkbox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="2번 체크박스"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/first_checkbox"/>

    <CheckBox
        android:id="@+id/third_checkbox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="3번 체크박스"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/second_checkbox"/>

    <CheckBox
        android:id="@+id/fourth_checkbox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="4번 체크박스"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/third_checkbox"/>

    <CheckBox
        android:id="@+id/fifth_checkbox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="5번 체크박스"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/fourth_checkbox"/>

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_marginBottom="40dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:background="@color/design_default_color_primary"
        android:text="버튼"
        android:textColor="@color/white"
        android:textSize="20sp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

 

이 화면에서 구현할 로직은 아래와 같다.

 

  • 1번 체크박스를 누르면 모든 체크박스가 선택되며 버튼 색이 바뀌고 활성화된다. 다시 누르면 모든 체크박스가 선택 해제되고 버튼 색이 원래대로 돌아온다
  • 2, 3번 체크박스가 활성화돼야 버튼 색이 바뀌고 활성화된다. 둘 중 하나라도 선택되지 않으면 버튼은 활성화되지 않는다
  • 4, 5번 체크박스가 모두 체크돼도 버튼은 활성화되지 않는다
  • 2번~5번 체크박스를 각각 눌러서 모두 선택하면 1번 체크박스가 자동으로 선택된다. 이후 하나라도 선택 해제되면 1번 체크박스는 선택 해제된다. 이 때 선택 해제된 체크박스가 2번 또는 3번이라면 버튼이 보라색으로 바뀌며 비활성화된다
  • 활성화된 버튼을 누르면 토스트가 출력된다. 비활성화일 땐 눌러도 아무 일도 일어나지 않는다

 

이걸 코드로 바꾸면 아래처럼 만들 수 있다.

 

import android.annotation.SuppressLint
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.example.kotlinprac.R
import com.jakewharton.rxbinding2.widget.RxCompoundButton
import kotlinx.android.synthetic.main.activity_rx_binding.*

class RxBindingActivity : AppCompatActivity() {

    private var isAllAgree: Boolean = false
    private var secondCheck: Boolean = false
    private var thirdCheck: Boolean = false
    private var fourthCheck: Boolean = false
    private var fifthCheck: Boolean = false

    private var firstCount = 0
    private var secondCount = 0
    private var thirdCount = 0
    private var fourthCount = 0
    private var fifthCount = 0

    @SuppressLint("CheckResult")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_rx_binding)

        RxCompoundButton.checkedChanges(first_checkbox)
            .subscribe { value ->
                firstCount++
                if (firstCount % 2 == 0 && value) {
                    setAllTrueOrFalse(true)
                } else {
                    setAllTrueOrFalse(false)
                }
            }

        RxCompoundButton.checkedChanges(second_checkbox)
            .subscribe { value ->
                secondCount++
                secondCheck = value
                changeButtonState(secondCheck && thirdCheck)
                setAllAgreeButtonValue()
                saveButtonStateAndReset(secondCount)
            }

        RxCompoundButton.checkedChanges(third_checkbox)
            .subscribe { value ->
                thirdCount++
                thirdCheck = value
                changeButtonState(secondCheck && thirdCheck)
                setAllAgreeButtonValue()
                saveButtonStateAndReset(thirdCount)
            }

        RxCompoundButton.checkedChanges(fourth_checkbox)
            .subscribe { value ->
                fourthCount++
                fourthCheck = value
                setAllAgreeButtonValue()
                saveButtonStateAndReset(fourthCount)
            }

        RxCompoundButton.checkedChanges(fifth_checkbox)
            .subscribe { value ->
                fifthCount++
                fifthCheck = value
                setAllAgreeButtonValue()
                saveButtonStateAndReset(fifthCount)
            }

        button.setOnClickListener {
            if (button.isEnabled) {
                Toast.makeText(this, "버튼 활성화", Toast.LENGTH_SHORT).show()
            }
        }
    }

    private fun setAllTrueOrFalse(value: Boolean) {
        if (value) {
            isAllAgree = true
            second_checkbox.isChecked = true
            third_checkbox.isChecked = true
            fourth_checkbox.isChecked = true
            fifth_checkbox.isChecked = true
            button.setBackgroundColor(ContextCompat.getColor(this, R.color.teal_700))
        } else {
            isAllAgree = false
            second_checkbox.isChecked = false
            third_checkbox.isChecked = false
            fourth_checkbox.isChecked = false
            fifth_checkbox.isChecked = false
            button.setBackgroundColor(ContextCompat.getColor(this, R.color.design_default_color_primary))
        }
    }

    private fun changeButtonState(value: Boolean) {
        if (value) {
            button.setBackgroundColor(ContextCompat.getColor(this, R.color.teal_700))
            button.isEnabled = true
        } else {
            button.setBackgroundColor(ContextCompat.getColor(this, R.color.design_default_color_primary))
            button.isEnabled = false
        }
    }

    private fun setAllAgreeButtonValue() {
        if (secondCheck && thirdCheck && fourthCheck && fifthCheck) {
            first_checkbox.isChecked = true
            button.isEnabled = true
        }
    }

    private fun saveButtonStateAndReset(clickCount: Int) {
        if (clickCount > 1 && clickCount % 2 != 0) {
            if (firstCount > 1 && first_checkbox.isChecked) {
                val mSecondCheck = second_checkbox.isChecked
                val mThirdCheck = third_checkbox.isChecked
                val mFourthCheck = fourth_checkbox.isChecked
                val mFifthCheck = fifth_checkbox.isChecked

                first_checkbox.isChecked = false

                second_checkbox.isChecked = mSecondCheck
                third_checkbox.isChecked = mThirdCheck
                fourth_checkbox.isChecked = mFourthCheck
                fifth_checkbox.isChecked = mFifthCheck
            }
        }
    }

}

 

반응형
Comments