티스토리 뷰
-공부내용 필기-
- Column 가로, 세로 중앙 배치 (이 Column외 다른 컴포저블 없는경우)
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {}
- Button 컴포저블은 기본적으로 보라색이다, Button 내부에 Image를 넣어 이미지가 있는 버튼을 만들수있지만 기본적으로 적용되는 보라색이 배경에 깔리게된다
- 클릭 가능한 컴포저블 만들기
- Button외 다른 컴포저블을 클릭할수있게 만드려면 해당 컴포저블에 clickable 수정자를 지정한다
Image(
painter = painterResource(drawableResourceId),
contentDescription = stringResource(contentDescriptionResourceId),
modifier = Modifier
.wrapContentSize()
.clickable(
onClick = onImageClick
)
)
- IconButton을 사용해도 이미지가 있는 버튼을 만들 수 있다
- 테두리는 modifier에 border를 주면됨
IconButton(
onClick = {
},
modifier = Modifier.border(//테두리
BorderStroke(2.dp, Color(105,205,216)),
shape= RoundedCornerShape(4.dp)
)
) {
Image(
painter = imageId,
contentDescription = descriptionId,
)
}
- 리컴포지션= 컴포저블이 다시 실행, 새로고침
- 리컴포지션이 되면 원래 이전에 있던 컴포저블 내부 변수값은 리셋된다
- 이전 컴포저블 내부 변수를 유지하려면 메모리에 저장해야한다 이때 remember 컴포저블을 사용함
- mutableStateOf를 컴포저블안에서 사용해 변수를 만들면 이 변수값이 변경될때 리컴포지션이 되도록 계속 관찰하게 된다(By using mutableStateOf values in a composable function, variables can be made into observables that schedule a recomposition when their value is changed.)
- 클릭 함수를 만들때 로직과 이미지 표시 부분을 나눈다면 로직에서 클릭 함수를 만들고 이미지 표시 컴포저블로 클릭 함수를 람다로 보내줄수있다
- 람다식을 처음 정의할땐 아래처럼
var onClickFun: ()->Unit={
stageNum++
tabNum=(2..4).random()
}
//var 변수명: 람다식 타입={바디}
//람다식 타입은 (매개변수들)->반환형
- 람다식에 다른 식을 넣을땐 처음 정의할때와 달리 타입 표시가 필요없으니깐 그냥 넣으면됨
onClickFun= {
tabNum--
if(tabNum==0)
stageNum++
}
-가장 처음엔 LemonadeApp()에 모든 로직과 ui 표시를 넣었는데 솔루션 코드를 보고 난 뒤 로직, ui를 분리하는게 좋아보여서 분리했다
package com.example.lemonade
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.lemonade.ui.theme.LemonadeTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
LemonadeTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
LemonadeApp()
}
}
}
}
}
@Preview(showBackground = true)
@Composable
fun LemonadeApp(){
var stageNum by remember{ mutableStateOf(0) }
var messageId= stringResource(id = R.string.tap_lemon)
var imageId= painterResource(id = R.drawable.lemon_tree)
var descriptionId= stringResource(id = R.string.lemon_tree)
var tabNum by remember { mutableStateOf(-1) }
var onClickFun: ()->Unit={
stageNum++
tabNum=(2..4).random()
}
when(stageNum){
1-> {
messageId=stringResource(id = R.string.keep_tapping)
imageId= painterResource(id = R.drawable.lemon_squeeze)
descriptionId= stringResource(id = R.string.lemon)
onClickFun= {
tabNum--
if(tabNum==0)
stageNum++
}
}
2-> {
messageId=stringResource(id = R.string.drink)
imageId= painterResource(id = R.drawable.lemon_drink)
descriptionId= stringResource(id = R.string.glass_of_lemonade)
}
3-> {
messageId=stringResource(id = R.string.start_again)
imageId= painterResource(id = R.drawable.lemon_restart)
descriptionId= stringResource(id = R.string.empty_glass)
}
}
TextAndImage(
messageId=messageId,
imageId=imageId,
descriptionId=descriptionId,
tabNum=tabNum,
onClickFun=onClickFun
)
}
@Composable
fun TextAndImage(
messageId:String,
imageId: Painter,
descriptionId:String,
tabNum:Int,
onClickFun: ()->Unit
){
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = messageId,
fontSize = 18.sp
)
Spacer(modifier = Modifier.height(16.dp))
IconButton(
onClick = onClickFun,
modifier = Modifier.border(
BorderStroke(2.dp, Color(105,205,216)),
shape= RoundedCornerShape(4.dp)
)
) {
Image(
painter = imageId,
contentDescription = descriptionId,
)
}
}
}
두번째는 이렇게 변수를 밖에 빼고 when에서 각 변수값 수정한 다음 맨 마지막에 TextAndImage라는 ui표시부분을 호출하도록 했는데 이렇게 하면 LemonadeApp()이 리컴포지션되면 항상 이 id를 담는 변수들이 초기화 되고 그다음 when에서 stageNum에 따라 변경된다, 가독성이 이게 더 좋을것 같아서 이렇게 해봤는데 오히려 줄 수만 많아지고 같은일 두번하게 만드는것 같아서 또 고쳤다
package com.example.lemonade
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.lemonade.ui.theme.LemonadeTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
LemonadeTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
LemonadeApp()
}
}
}
}
}
@Preview(showBackground = true)
@Composable
fun LemonadeApp(){//전체를 감싸며 로직을 처리한다
var stageNum by remember{ mutableStateOf(0) }
var tabNum by remember { mutableStateOf(-1) }
when(stageNum){//stageNum에 따라 표시되는 ui가 달라진다
0->{//레몬나무에서 레몬 선택하는 화면
TextAndImage(
messageId=stringResource(id = R.string.tap_lemon),
imageId= painterResource(id = R.drawable.lemon_tree),
descriptionId= stringResource(id = R.string.lemon_tree),
) {//전달할 onClick 처리 함수
stageNum++
tabNum=(2..4).random()
}
}
1-> {//레몬즙을 짜는 화면
TextAndImage(
messageId=stringResource(id = R.string.keep_tapping),
imageId= painterResource(id = R.drawable.lemon_squeeze),
descriptionId= stringResource(id = R.string.lemon),
) {
tabNum--
if(tabNum==0)
stageNum++
}
}
2-> {//레몬에이드를 마시는 화면
TextAndImage(
messageId=stringResource(id = R.string.drink),
imageId= painterResource(id = R.drawable.lemon_drink),
descriptionId= stringResource(id = R.string.glass_of_lemonade),
) {
stageNum++
}
}
3-> {//빈컵 화면
TextAndImage(
messageId=stringResource(id = R.string.start_again),
imageId= painterResource(id = R.drawable.lemon_restart),
descriptionId= stringResource(id = R.string.empty_glass),
) {
stageNum=0
}
}
}
}
@Composable
fun TextAndImage(//ui표기를 담당한다
messageId:String,
imageId: Painter,
descriptionId:String,
onClickFun: ()->Unit //()->Unit 타입의 함수를 매개변수로 받는다
){
Column(
modifier = Modifier.fillMaxWidth(),//가로를 차지가능한 만큼 다 차지한다
horizontalAlignment = Alignment.CenterHorizontally,//가로중앙
verticalArrangement = Arrangement.Center//세로중앙
) {
Text(
text = messageId,
fontSize = 18.sp
)
Spacer(modifier = Modifier.height(16.dp))
IconButton(
onClick = onClickFun,
modifier = Modifier.border(
BorderStroke(2.dp, Color(105,205,216)),
shape= RoundedCornerShape(4.dp)
)
) {
Image(
painter = imageId,
contentDescription = descriptionId,
)
}
}
}
궁금한점...
LemonadeApp()에서 TextAndImage()를 호출할때 매개변수로 tabNum, stageNum을 전달했다
그런데 이게 전달할때 ... 주소로 전달되어서 다른 호출된 함수에서 값 변경했을때 원본변수값도 변경이 된건가?
실험을 하려고 그냥 일반 변수인 test를 만들어서 클릭할때마다 test++되게 하고 test도 TextAndImage로 전달했는데 걔는 변경이 안되는거 같음
그리고 여기서 ui, 로직처리 분리한게 https://origogi.github.io/android/compose-state/ 여기서 설명하는
State Hoisting 일까?
-참고사이트
GitHub - google-developer-training/basic-android-kotlin-compose-training-lemonade
Contribute to google-developer-training/basic-android-kotlin-compose-training-lemonade development by creating an account on GitHub.
github.com
https://origogi.github.io/android/compose-state/
[Android][Compose] State 관리
origogi.github.io
'공부 > ComposeCamp 2022' 카테고리의 다른 글
Unit 2 : 맞춤 팁 계산기 (0) | 2022.11.29 |
---|---|
unit 2: Compose 상태 소개, Tip Time 계산기 만들기 (0) | 2022.11.28 |
unit2 : 안드로이드 스튜디오 디버거 사용하기 (0) | 2022.11.27 |
unit 2: 상호작용 Dice Roller 앱 만들기 (0) | 2022.11.23 |
unit 2: 연습 Kotlin 기초 (0) | 2022.11.23 |