Composable의 상태
구성 가능한(Composable) 함수는 remember composable을 사용하여 메모리에 단일 객체를 저장할 수 있습니다.
remember에 의해 계산된 값은 초기 컴포지션 중에 컴포지션에 저장되고 저장된 값은 리컴포지션 중에 반환됩니다.
remember는 변경 가능한 객체뿐만 아니라 변경할 수 없는 객체를 저장하는데 사용할 수 있습니다.
* remember는 객체를 컴포지션에 저장하고, remember를 호출한 컴포저블이 컴포지션에서 삭제되면 그 객체를 잊습니다.
interface MutableState<T> : State<T> {
override var value: T
}
MutableState는 State를 상속하고 interface입니다. 안에 멤버변수로 value를 가지고 있습니다.
value가 변경되면 value를 읽는 구성 가능한 함수의 re-composition이 예약됩니다.
Box안에 Text의 경우 moneyCounter가 변경될때마다 Text가 재구성됩니다.
Composable에서 MutableState 객체를 선언하는 데는 세 가지 방법이 있습니다.
- val mutableState = remember { mutableStateOf(default) }
- var value by remember { mutableStateOf(default) }
- val (value, setValue) = remeber { mutableStateOf(default) }
이러한 선언은 동일한 것이고 서로 다른 용도의 상태를 사용하기 위한 구문으로 제공됩니다. 작성 중인 컴포저블에서 가장 읽기 쉬운 코드를 생성하는 선언을 선택하면 됩니다.
지난 시간에는 두 번째 방법으로 moneyCount를 선언했는데요
var moneyCounter by remeber { mutableStateOf(0) }로 선언을 했었는데요!
JETPACK COMPOSE: 터치하면 돈이 올라가는 앱을 만들어보자 - 2
이번 시간에는 첫 번째 방법으로 선언하는 방법을 살펴보겠습니다.
fun CreateCircle() {
// var moneyCounter by remember {
// mutableStateOf(0)
// }
var moneyCounter = remember { // [1]
mutableStateOf(0)
}
Card(modifier = Modifier
.padding(3.dp)
.size(100.dp)
.clickable {
//moneyCounter += 1
moneyCounter.value += 1 // [2]
//Log.d("Counter", "CreateCircle : $moneyCounter")
Log.d("Counter", "CreateCircle : ${moneyCounter.value}")
}
,
shape = CircleShape,
elevation = 4.dp
) {
Box(contentAlignment = Alignment.Center) {
//Text(text = "Tap $moneyCounter", modifier = Modifier)
Text(text = "Tap ${moneyCounter.value}", modifier = Modifier) // [3]
}
}
}
다시 선언된 moenyCounter와 값을 1씩 증가시키는 부분에 주목해봅시다
- [1] by가 없이 = remember로 moneyCounter를 선언해주었습니다.
- [2] moneyCounter +=1 하는 게 아니라 moneyCounter.value += 1을 해주어야 정상 동작됩니다. 위에 살펴봤듯이 mutableStateOf()는 value를 멤버 변수로 갖습니다.
- [3] moneyCounter를 출력할 때도 value를 출력해야 숫자가 출력됩니다.
이제 tap을 누를 때마다 달러가 변화하도록 하고 싶은데 어떻게 해야 될까요?
@Composable
fun MyApp() {
Surface(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(),
color = Color(0xFF4666d0)) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
)
{
Text(text = "$100", style = TextStyle(
color = Color.White,
fontSize = 35.sp,
fontWeight = FontWeight.ExtraBold
))
Spacer(modifier=Modifier.height(130.dp))
CreateCircle()
}
}
}
달러(현재 $100)는 Myapp()의 Text에 있고 Tap 자체는 CreateCircle()에서 호출되는 Composable이기 때문에 moneyCounter의 위치를 MyApp()으로 변경해야 두 곳에서 사용할 수 있게 됩니다.
@Composable
fun MyApp() {
var moneyCounter = remember {
mutableStateOf(0)
}
Surface(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(),
color = Color(0xFF4666d0)) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
)
{
Text(text = "$${moneyCounter.value}", style = TextStyle(
color = Color.White,
fontSize = 35.sp,
fontWeight = FontWeight.ExtraBold
))
Spacer(modifier=Modifier.height(130.dp))
CreateCircle(moneyCounter = moneyCounter.value) { newValue ->
moneyCounter.value = newValue + 1
}
}
}
}
우선 moneyCounter의 위치를 옮기고 Text에서는 moneyCounter의 value값을 출력하도록 수정합니다.
그리고 CreateCircle에 moneyCounter.value를 넘기고 function이 call 될 때마다 수행할 lamda function을 만드는데 그냥 넘어온 값(newValue)에 +1을 한 값을 다시 moneyCounter.value에 저장합니다.
@Composable
fun CreateCircle(moneyCounter: Int = 0, updateMoneyCounter: (Int) -> Unit) {
Card(modifier = Modifier
.padding(3.dp)
.size(100.dp)
.clickable {
//moneyCounter += 1
updateMoneyCounter(moneyCounter)
Log.d("Counter", "CreateCircle : $moneyCounter")
}
,
shape = CircleShape,
elevation = 4.dp
) {
Box(contentAlignment = Alignment.Center) {
Text(text = "Tap $moneyCounter", modifier = Modifier)
}
}
}
CreateCircle에 두 번째 매개변수로 lamda function이 들어가 있는데 Int를 받아서 Unit를 return 합니다.
.clickable(클릭이 되면) updateMoneyCounter에 현재 받은 moneyCounter를 인자로 넘겨줍니다.
이제 클릭되는 Count만큼 달러도 update가 되는 것을 볼 수 있습니다!
이렇게 구성을 하면 mutableState를 넘기는 게 아니라 Int만 넘기면 되기 때문에 간단합니다.
이렇게 구성을 하면 또 무엇을 할 수 있을까요?
@Composable
fun MyApp() {
var moneyCounter = remember {
mutableStateOf(0)
}
Surface(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(),
color = Color(0xFF4666d0)) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
)
{
Text(text = "$${moneyCounter.value}", style = TextStyle(
color = Color.White,
fontSize = 35.sp,
fontWeight = FontWeight.ExtraBold
))
Spacer(modifier=Modifier.height(130.dp))
CreateCircle(moneyCounter = moneyCounter.value) { newValue ->
moneyCounter.value = newValue + 1
}
if(moneyCounter.value > 10) {
Text("Over $10 !!")
}
}
}
}
if문을 넣어서 원하는 값이 되면 Composable을 추가할 수 있습니다.
moneyCounter.value가 10보다 클 때만 위와 같이 Text를 출력하게 할 수도 안 할 수도 있게 됩니다.
'Android > Jetpack Compose App' 카테고리의 다른 글
JETPACK COMPOSE: 팁 계산기 만들기 - 2 (0) | 2022.02.08 |
---|---|
JETPACK COMPOSE: 팁 계산기 만들기 - 1 (0) | 2022.01.26 |
JETPACK COMPOSE: 터치하면 돈이 올라가는 앱을 만들어보자 - 2 (0) | 2022.01.21 |
JETPACK COMPOSE: 터치하면 돈이 올라가는 앱을 만들어보자 - 1 (0) | 2022.01.20 |
Android studio 기본 예제로 알아보는 Jetpack Compose의 기초 (0) | 2022.01.11 |
댓글