Android Jetpack
계산기 만들어보기 (Livedata+ViewModel+DataBinding+BindingAdapter)
wdadaww
2023. 2. 15. 00:11
+,- 버튼을 만들어서 Edittext에 숫자를 넣고 실시간으로 계산된 값을 보여주는 계산기를 Livedata와 Databinding을 이용해보겟습니다.
- activity_main_xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="viewmodel"
type="com.example.viewmodel.MyViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewmodel.mapCounter.toString()}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/editText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toStartOf="@id/plusbutton"
app:layout_constraintTop_toBottomOf="@id/textview" />
<Button
android:id="@+id/minusbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="빼기"
app:layout_constraintTop_toBottomOf="@id/textview"
app:layout_constraintEnd_toEndOf="parent"/>
<Button
android:id="@+id/plusbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="더하기"
app:layout_constraintEnd_toStartOf="@id/minusbutton"
app:layout_constraintTop_toBottomOf="@id/textview" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
EditText에 숫자를 넣고 더하기 ,빼기 버튼을 누르면 계산된 값을 TextView로 보여주는 간단히 계산기 UI 만들어 보았습니다.
- ViewModel 클래스
package com.example.viewmodel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
enum class ButtomState {
Plus, Minus
}
class MyViewModel
: ViewModel() {
private val liveCounter = MutableLiveData(0)
val mapCounter = Transformations.map(liveCounter) { Counter ->
"${Counter}입니다"
}
fun liveDataCounter(state: ButtomState, number: Int) {
when (state) {
ButtomState.Plus ->
liveCounter.value = liveCounter.value?.plus(number)
ButtomState.Minus ->
liveCounter.value = liveCounter.value?.minus(number)
}
}
}
liveDataCounter 함수를 보면 버튼의 상태에따라 MutableLivedata의 값을 새롭게 초기화해주고있다.
- MainActivity
package com.example.viewmodel
import android.os.Bundle
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import com.example.viewmodel.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var myViewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//데이터바인딩 적용.
val binding =
DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
myViewModel = ViewModelProvider(this)[MyViewModel::class.java]
//LiveData를 관측하기위해 lifecycleowner정의
//xml 데이터뷰를 가지고있는 viewmodel 를지정.
binding.lifecycleOwner = this
binding.viewmodel = myViewModel
// ViewModel + Livedata 적용
binding.plusbutton.setOnClickListener {
val input = binding.editText.text.toString().toInt()
myViewModel.liveDataCounter(ButtomState.Plus, input)
binding.minusbutton.setOnClickListener {
val input = binding.editText.text.toString().toInt()
myViewModel.liveDataCounter(ButtomState.Minus, input)
}
}
}
}
버튼 setOnClickListener를 통해 ViewModel에서 구현했던 데이터를 업데이트해주는 liveDataCounter 함수를 호출 해주면된다.
- 결과물
- 바인딩 어댑터를 사용하여 사용자 지정 특성 만들기
- activity_mainl.xml에 프로그래스바 를 추가해준다
- BindingAdapter 클래스를 만들어줍니다.
package com.example.viewmodel.adapter
import android.widget.ProgressBar
import androidx.databinding.BindingAdapter
@BindingAdapter(value = ["app:progressScaled","android:max"], requireAll = true)
fun setProgress(progressBar: ProgressBar, Counter: Int, max:Int){
progressBar.progress = (Counter*2).coerceAtMost(max)
}