이번 게시글은 안드로이드 라이브 데이터에 대한 지식이 있다는 가정 하에 진행합니다.
라이브 데이터는 옵저버 패턴으로써 데이터.observe 함수로 데이터.value 값의 변경을 감지해서 값이 변경될 때 로직을 실행시키는 타입입니다.
필요한 리소스들입니다.
all_round.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFFFF" />
<corners android:radius="10dp" />
</shape>
btn_white.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true">
<shape android:shape="rectangle">
<solid android:color="#FFFFFF" />
<corners android:radius="10dp" />
</shape>
</item>
<item android:state_enabled="false">
<shape android:shape="rectangle">
<solid android:color="#eeeeee" />
<corners android:radius="10dp" />
</shape>
</item>
</selector>
signin_checkbox.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_check_01" android:state_checked="true" />
<item android:top="10dp" android:right="10dp" android:drawable="@drawable/check_cancel" android:state_checked="false" />
</selector>
ic_check_01.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="28dp"
android:height="28dp"
android:viewportWidth="28"
android:viewportHeight="28">
<path
android:pathData="M14,2A12,12 0,1 0,26 14,12 12,0 0,0 14,2ZM12.5,18.91l-4.71,-4.7 1.42,-1.42 3.29,3.3 6.29,-6.3 1.42,1.42Z"
android:fillColor="#9943fc"/>
</vector>
레이아웃
<?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:id="@+id/sign_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".navigation.review.WriteReviewActivity"
android:background="@color/white">
<ImageButton
android:id="@+id/activity_sign_button_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/app_margin_start"
android:contentDescription="@string/back"
android:layout_marginTop="50dp"
android:background="@drawable/back_01"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:text="tv_3"
android:id="@+id/activity_sign_textView_1"
android:layout_width="match_parent"
android:layout_height="38dp"
android:layout_marginStart="@dimen/app_margin_start"
android:layout_marginTop="10dp"
android:textSize="22sp"
android:fontFamily="@font/noto_bold"
android:includeFontPadding="false"
android:textColor="#202020"
android:textAlignment="textStart"
app:layout_constraintTop_toBottomOf="@+id/activity_sign_button_back"
app:layout_constraintLeft_toLeftOf="parent" />
<TextView
android:id="@+id/activity_sign_textView_2"
android:text="tv_4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="14dp"
android:layout_marginStart="@dimen/app_margin_start"
android:textSize="12sp"
android:fontFamily="@font/noto_medium"
android:includeFontPadding="false"
android:textAlignment="textStart"
app:layout_constraintTop_toBottomOf="@+id/activity_sign_textView_1" />
<EditText
android:id="@+id/activity_sign_editText"
android:layout_width="match_parent"
android:layout_height="50dp"
android:padding="10dp"
android:layout_marginHorizontal="@dimen/app_margin_start"
android:hint="@string/signIn_phone_hint"
android:inputType="phone"
android:background="@null"
android:textSize="20sp"
android:fontFamily="@font/noto_bold"
android:includeFontPadding="false"
android:maxLength="13"
android:maxLines="1"
app:layout_constraintTop_toBottomOf="@+id/activity_sign_textView_2"
android:autofillHints="" />
<LinearLayout
android:id="@+id/sign_progress_bar"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="match_parent"
android:layout_height="4dp"
android:layout_marginHorizontal="23dp"
android:background="#E4E4E4"
android:orientation="horizontal"
android:layout_marginTop="190dp" />
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/activity_sign_checkBox1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/app_margin_start"
android:scaleX="0.7"
android:scaleY="0.7"
android:button="@drawable/signin_checkbox"
android:padding="5dp"
app:layout_constraintTop_toBottomOf="@+id/activity_sign_checkBox4"
app:layout_constraintLeft_toLeftOf="parent" />
<TextView
android:id="@+id/activity_sign_checkBox1_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:fontFamily="@font/noto_medium"
android:includeFontPadding="false"
app:layout_constraintStart_toEndOf="@id/activity_sign_checkBox1"
app:layout_constraintTop_toTopOf="@id/activity_sign_checkBox1"
app:layout_constraintBottom_toBottomOf="@id/activity_sign_checkBox1"
android:text="@string/check_weat_service" />
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/activity_sign_checkBox2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/app_margin_start"
app:layout_constraintLeft_toLeftOf="parent"
android:button="@drawable/signin_checkbox"
android:scaleX="0.7"
android:scaleY="0.7"
android:padding="5dp"
app:layout_constraintTop_toBottomOf="@+id/activity_sign_checkBox1" />
<TextView
android:id="@+id/activity_sign_checkBox2_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:fontFamily="@font/noto_medium"
android:includeFontPadding="false"
app:layout_constraintTop_toTopOf="@id/activity_sign_checkBox2"
app:layout_constraintStart_toEndOf="@id/activity_sign_checkBox2"
app:layout_constraintBottom_toBottomOf="@id/activity_sign_checkBox2"
android:text="@string/check_privacy" />
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/activity_sign_checkBox3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/app_margin_start"
android:scaleX="0.7"
android:scaleY="0.7"
android:button="@drawable/signin_checkbox"
android:padding="5dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/activity_sign_checkBox2" />
<TextView
android:id="@+id/activity_sign_checkBox3_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:fontFamily="@font/noto_medium"
android:includeFontPadding="false"
app:layout_constraintTop_toTopOf="@id/activity_sign_checkBox3"
app:layout_constraintStart_toEndOf="@id/activity_sign_checkBox3"
app:layout_constraintBottom_toBottomOf="@id/activity_sign_checkBox3"
android:text="@string/check_location_confirm" />
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/activity_sign_checkBox4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:padding="5dp"
android:layout_marginStart="@dimen/app_margin_start"
android:scaleX="0.7"
android:scaleY="0.7"
android:button="@drawable/signin_checkbox"
app:layout_constraintTop_toBottomOf="@+id/sign_progress_bar"
app:layout_constraintLeft_toLeftOf="parent" />
<TextView
android:id="@+id/activity_sign_checkBox4_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:fontFamily="@font/noto_medium"
android:includeFontPadding="false"
app:layout_constraintTop_toTopOf="@id/activity_sign_checkBox4"
app:layout_constraintStart_toEndOf="@id/activity_sign_checkBox4"
app:layout_constraintBottom_toBottomOf="@id/activity_sign_checkBox4"
android:text="@string/check_all" />
<LinearLayout
android:id="@+id/activity_sign_button_linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentBottom="true"
app:layout_constraintBottom_toBottomOf="parent">
<Button
android:id="@+id/activity_sign_button"
android:layout_gravity="center"
android:layout_width="330dp"
android:layout_height="56dp"
android:layout_marginBottom="24dp"
android:textStyle="bold"
android:background="@drawable/btn_white" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
기존 코드를 재활용해서 만든 코드이기 때문에 font가 들어가 있는데 font는 지우고 하셔도 무방합니다.
font 때문에 에러가 난다면 지우고 실행해주세요.
휴대폰 번호를 입력하는 editText와 4개의 checkbox, 넘어가는 버튼으로 구성했습니다.
checkbox의 background를 selector로 설정하여 체크되었을 때의 이미지와 체크되지 않았을 때의 이미지를 구분했습니다.
로직 코드입니다.
class SignActivity : AppCompatActivity() {
private lateinit var token: String
private lateinit var phone: String
private var isCheckBoxChecked1: MutableLiveData<Int> = MutableLiveData()
private var isCheckBoxChecked2: MutableLiveData<Int> = MutableLiveData()
private var isCheckBoxChecked3: MutableLiveData<Int> = MutableLiveData()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sign)
initView()
setStartButtonOnClickListener()
}
private fun initView() {
activity_sign_editText.requestFocus()
(setCheckBox1TextOnClickListener())
activity_sign_checkBox2_text.setOnClickListener(setCheckBox2TextOnClickListener())
activity_sign_checkBox3_text.setOnClickListener(setCheckBox3TextOnClickListener())
activity_sign_checkBox1.setOnCheckedChangeListener(setOnCheckedChangedListener1())
activity_sign_checkBox2.setOnCheckedChangeListener(setOnCheckedChangedListener2())
activity_sign_checkBox3.setOnCheckedChangeListener(setOnCheckedChangedListener3())
activity_sign_checkBox4.setOnCheckedChangeListener(setOnCheckedChangedListener4())
activity_sign_textView_1.text = "전화번호를 입력해주세요."
activity_sign_textView_2.text = "회원가입 및 로그인에 필요합니다."
activity_sign_editText.text = null
activity_sign_editText.hint = "01000000000"
activity_sign_editText.addTextChangedListener(PhoneNumberFormattingTextWatcher())
sign_progress_bar.setBackgroundColor(Color.parseColor("#E0E0E0"))
activity_sign_button.isEnabled = false
activity_sign_button.text = "약관에 동의해주세요"
activity_sign_editText.addTextChangedListener {
println(it?.length)
if (it?.length == 13 && isCheckBoxChecked1.value == 1 && isCheckBoxChecked2.value == 1 && isCheckBoxChecked3.value == 1)
runOnUiThread {
activity_sign_button.isEnabled = true
activity_sign_button.text = "다음"
}
else if (it?.length!! <= 12) {
activity_sign_button.isEnabled = false
activity_sign_button.text = "전화번호를 입력해주세요"
}
}
// 체크박스를 배열에 넣어서 for문으로 코드량을 줄이고자 했으나 옵저버가 제대로 붙지 않음
isCheckBoxChecked1.observe(this, Observer {
checkboxObserver(it)
})
isCheckBoxChecked2.observe(this, Observer {
checkboxObserver(it)
})
isCheckBoxChecked3.observe(this, Observer {
checkboxObserver(it)
})
activity_sign_button.setTextColor(Color.parseColor("#000000"))
activity_sign_button.background = ContextCompat.getDrawable(this, R.drawable.btn_white)
sign_layout.setBackgroundColor(Color.parseColor("#FFFFFF"))
}
private fun checkboxObserver(it: Int) {
println("observe checkBox")
if (it == 0) {
activity_sign_button.isEnabled = false
activity_sign_button.text = "약관에 동의해주세요"
} else if (isCheckBoxChecked1.value == 0 || isCheckBoxChecked2.value == 0 || isCheckBoxChecked3.value == 0) {
activity_sign_button.isEnabled = false
activity_sign_button.text = "약관에 동의해주세요"
} else if (isCheckBoxChecked1.value == 1 && isCheckBoxChecked2.value == 1 && isCheckBoxChecked3.value == 1 && activity_sign_editText.text.length == 13) {
activity_sign_button.isEnabled = true
activity_sign_button.text = "다음"
} else {
activity_sign_button.isEnabled = false
activity_sign_button.text = "약관에 동의해주세요"
}
}
private fun setStartButtonOnClickListener() {
activity_sign_button.setOnClickListener {
if (isCheckBoxChecked1.value == 0 || isCheckBoxChecked2.value == 0 || isCheckBoxChecked3.value == 0) {
Toast.makeText(applicationContext, "이용약관을 모두 체크해주세요!", Toast.LENGTH_LONG)
.show()
return@setOnClickListener
}
phone = activity_sign_editText.text.toString()
if (phone.length != 13) {
runOnUiThread {
Toast.makeText(
applicationContext,
"전화번호를 정확히 입력해주세요",
Toast.LENGTH_SHORT
).show()
}
return@setOnClickListener
}
}
}
private fun setCheckBox1TextOnClickListener(): View.OnClickListener? {
return View.OnClickListener {
val intent = Intent(this, TermsActivity::class.java)
AppCompatActivity().startActivityForResult(intent, 1)
}
}
private fun setCheckBox2TextOnClickListener(): View.OnClickListener? {
return View.OnClickListener {
val intent = Intent(this, TermsActivity::class.java)
AppCompatActivity().startActivityForResult(intent, 2)
}
}
private fun setCheckBox3TextOnClickListener(): View.OnClickListener? {
return View.OnClickListener {
val intent = Intent(this, TermsActivity::class.java)
AppCompatActivity().startActivityForResult(intent, 3)
}
}
private fun setOnCheckedChangedListener1(): CompoundButton.OnCheckedChangeListener? {
return CompoundButton.OnCheckedChangeListener { _, isChecked ->
isCheckBoxChecked1.value = if (isChecked) 1
else 0
}
}
private fun setOnCheckedChangedListener2(): CompoundButton.OnCheckedChangeListener? {
return CompoundButton.OnCheckedChangeListener { _, isChecked ->
isCheckBoxChecked2.value = if (isChecked) 1
else 0
}
}
private fun setOnCheckedChangedListener3(): CompoundButton.OnCheckedChangeListener? {
return CompoundButton.OnCheckedChangeListener { _, isChecked ->
isCheckBoxChecked3.value = if (isChecked) 1
else 0
}
}
private fun setOnCheckedChangedListener4(): CompoundButton.OnCheckedChangeListener? {
return CompoundButton.OnCheckedChangeListener { _, isChecked ->
if (isChecked) {
activity_sign_checkBox1.isChecked = true
activity_sign_checkBox2.isChecked = true
activity_sign_checkBox3.isChecked = true
isCheckBoxChecked1.value = 1
isCheckBoxChecked2.value = 1
isCheckBoxChecked3.value = 1
} else {
activity_sign_checkBox1.isChecked = false
activity_sign_checkBox2.isChecked = false
activity_sign_checkBox3.isChecked = false
isCheckBoxChecked1.value = 0
isCheckBoxChecked2.value = 0
isCheckBoxChecked3.value = 0
}
}
}
}
체크박스 4개와 일괄적으로 체크하는 체크박스 한개가 존재하므로 일괄 체크박스를 제외한 나머지 세개의 체크박스를 라이브데이터로 만들어줍니다. 이후 체크박스가 모두 체크되고 휴대폰 번호가 입력되면 인증 번호가 활성화 되도록 만들었습니다. 일괄 버튼은 각 체크박스의 체크값과 체크를 확인하기 위한 값을 모두 변경해줍니다.
여기서 주의할 점이 checkbox에 observer를 붙일 때 이를 for문으로 붙여서 코드량을 줄이려고 시도했으나 for문으로 하면 라이브 데이터의 observer가 데이터 변경을 감지하지 못합니다. 그래서 체크를 풀어도 버튼이 비활성화 되지 않는 이슈가 발생합니다. 이유는 잘 모르겠지만 for문의 구조 때문이거나 observer의 생명주기와 관련된 문제가 아닐까 싶습니다.
결과적으로는 잘 작동합니다!!
공감과 댓글, 질문은 블로거에게 큰 힘이 됩니다.
'App > 개발' 카테고리의 다른 글
[안드로이드] 비트맵 파일을 파일 타입으로 변환하기 (bitmap to file) (1) | 2020.11.19 |
---|---|
[안드로이드] 클릭시 별점의 색이 변하는 가게 평가 레이아웃 만들기(버튼 커스텀) (0) | 2020.10.21 |
[안드로이드] 세개 버튼으로 이루어진 애니메이션 팝업 버튼 만들기 (0) | 2020.10.15 |
[안드로이드] 6자리 블록으로 만들어진 인증번호 입력 만들기(자동 넘김, 자동 지움) (0) | 2020.10.13 |
[안드로이드] 뷰페이저 페이지 변경될 때 레이아웃 적용하기 (0) | 2020.09.20 |