@Composable ๊ณผ Recomposition, ๊ทธ๋ฆฌ๊ณ Modifier
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
์ปดํฌ์ ๋ธ ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ํจ์๋ UI๋ฅผ ์์ฑํ๊ณ , ๊ด๋ฆฌํ ์ ์๋ ํจ์๊ฐ ๋๋ค. ์ด ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ํจ์๋ ์ปดํ์ผ๋ฌ๊ฐ ๋ฐ๋ก ์ฒ๋ฆฌ๋ฅผ ํ๊ณ , ๋ฐํ์๋ ํตํฉํ๊ธฐ ์ํด ์ฝ๋๊ฐ ๋ฐ๋ก ์์ฑ๋๋ค. ์ค์ํ ์ ์ UI๋ฅผ ์์ฑํ๋๋ฐ, returnํ์์ด ์๋ emit ํ์์ด์ด์ ๋ฐํ๊ฐ์ด ๋ฐ๋ก ์๋ค๋ ์ ์ด๋ค.
UI๋ฅผ ๊ตฌ์ฑํ๋ ์์์ด๊ธฐ ๋๋ฌธ์ Recomposition์ ๋ํ ๊ฐ๋ ๋ ์ฎ์ฌ์๋ค. ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋๋ฉด Compose๋ ์ ๋ฐ์ดํฐ๋ก Composableํจ์๋ฅผ ๋ค์ ์คํํ์ฌ ์ ๋ฐ์ดํธ๋ UI๋ฅผ ๋ง๋ ๋ค. ๊ฒฝ์ฐ์ ๋ฐ๋ผ ํ์ํ ๋ถ๋ถ๋ง UI ์ ๋ฐ์ดํธํด์ ์ฑ๋ฅ์ ์ต์ ํํด์ฃผ๋๋ฐ, ๊ฐ์ฒด์ reference๋ง ๋น๊ตํ๋๊ฒ ์๋๋ผ ๋ด์ฉ๊น์ง ๋น๊ตํด์ ๋ด์ฉ์ด ๊ฐ์๊ฒฝ์ฐ ๋ฐ๋ก ์ฌ๊ตฌ์ฑ์ ํ์ง ์๋๋ค. ๊ทธ๋ผ ํ์ํ ๋ถ๋ถ๋ง ์ด๋ป๊ฒ ๊ฐ์งํ ๊น? ๊ทธ๊ฑด ์ํ ๊ฐ์ฒด์ ๋ฌ๋ ค์๋ค. MutableState, State๋ก ๊ฐ์ธ์ง ์ํ๊ฐ์ฒด๊ฐ ์๋๋ฐ, ์๋ค๊ฐ UI recomposition์ ํธ๋ฆฌ๊ฑฐํ๋ ๊ฐ์ฒด๋ค์ด๋ค.
์ด ๊ฐ์ฒด๋ค์ ๊ฐ ๋ณ๊ฒฝ์ด ๋ฐ์ํ ๋ Compose ์์คํ ์ด ์ ์ ์๋ค. ๋ remeber๊ฐ ๋ถ์ ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ์ด์ ์ฐ์ฐ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์์ ์ฌ์ฉํ๋๊ฒ ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ๋ฆฌ์ปดํฌ์ง์ ์ ๋ฐฉ์งํ๋ ํจ๊ณผ๊ฐ ์๋ค.
Column, Row, Box ์ปดํฌ์ ๋ธ์ ๋ชจ๋ ์ปจํ ์ด๋๋ค.
@Preview(showBackground = true)
@Composable
fun UserProfile() {
Column {
Text("์ ์ ")
Text("abcd@a.b")
var likes by remember { mutableStateOf(0) }
Text("Likes: $likes")
Button(onClick = { likes++ }) {
Text("Like")
}
}
}
@Preview๋ ์ ์ ํ๋ฉด์ ๋ฏธ๋ฆฌ ๋ณด์ฌ์ฃผ๋ ์ด๋ ธํ ์ด์ ์ผ๋ก, ์ค ๊ธฐ๊ธฐ ํ๋ฉด์ฒ๋ผ ๋ณด๊ณ ์ถ๋ค๋ฉด ์๋์ ๊ฐ์ด ์ค์ ํ๋ฉด ๋๋ค.
@Preview(showBackground = true, widthDp = 320)
์ฝ๋๋ก ๋์์์, ์ฌ๊ตฌ์ฑ์ด ๋๋ ๋ถ๋ถ์ `Text("Likes: $likes")` ์ด๋ถ๋ถ์ด๋ค. Text๋ก Like๊ฐ ์ ํ์๋ Button์ ๋๋ฅด๋ฉด likes๊ฐ์ด ์ฆ๊ฐํด์ ์ด TextComposable์ด ์ฌ๊ตฌ์ฑ๋๋ค. UserProfile Composable ์ ์ฒด๊ฐ ์ฌ๊ตฌ์ฑ๋์ง๋ ์๋๋ค. ์ฌ๊ธฐ์๋ ๋ฐ๋ก ์๋ง๋ค์์ง๋ง, like๋ฅผ ๋ณ๊ฒฝํ๋๋ฐ ์ด์ ๊ณผ ๊ฐ์ด ๊ฐ๋ค๋ฉด ์ฌ๊ตฌ์ฑ์ด ์ผ์ด๋์ง ์๋๋ค.
`var likes by remember { mutableStateOf(0) }`
์ด ๋ถ๋ถ์ด ์ด๋ฒ Composable์ ํต์ฌ์ด๋ค. by๋ก ์์์ํจ๊ฒ๋ถํฐ ๋ด์ผ๋๋ค.
`val likes = remember { mutableStateOf(0) }`
์ด๊ฒ ์์์ํค๊ธฐ ์ ํํ๋ค. MutableState๊ฐ์ remember๋ก ๊ฐ์ธ์ likes ์ ํ ๋นํ ํํ๋ก, ๊ฐ์ ์ ๊ทผํ ๋๋ง๋ค .value ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํด์ผ๋๋ค. get, set์ด MutableState ๊ฐ์ฒด ์์ ์๋๋ฐ ๊ฑฐ๊ธฐ๊ฒ value ํ๋กํผํฐ๋ก ์ ๊ทผํ๋ค๊ณ ๋ณด๋ฉด ๋๋ค. LiveData๋ฅผ ์ฌ์ฉํ ๋ ๋ดค๋ ๊ฒฝ์ฐ๋ค. remember๋ก ๊ฐ์ธ๊ฒ ๋๋ฉด, recomposition ์ฌ์ด์์ ์ํ๋ฅผ ์ ์งํ ์ ์๋ค. ์ด๊ธฐํ ํ ๋๋ง ๋๋ค ๋ด๋ถ์ ์ฝ๋๋ฅผ ์คํํ๊ณ , ์ฌ๊ตฌ์ฑ์ด ๋ฐ์ํ ๋๋ ์ ์ฅ๋ ๊ฐ์ ๋ฐํํ๋ ํํ๋ค. ๋ฐ๋ผ์ ๋งค๋ฒ MutableState๊ฐ์ฒด๋ฅผ ๋ฐฐ์ ํด์ ์ฐ๋๊ฒ ์๋๋ผ remeber๋ ๊ฑธ ๊บผ๋ด์ ์ฐ๊ฒ ๋๋ค.
by๋ก ์์ํ๊ฒ ๋๋ฉด, get, set์ ์ ๊ทผํ๊ธฐ ์ํด value ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ท์ฐฎ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ง ์์๋ ๋๋ค. ๋ฐ๋ก likes๋ก ์ฌ์ฉ๊ฐ๋ฅํ๋ค. `likes.value = likes.value+1` ์ด `likes++` ๋ก ๋ฐ๋์๋ค๊ณ ์๊ฐํ๋ฉด ์ฒด๊ฐ๋ ๊ฒ์ด๋ค.
# Modifier
`Modifier`๋ Compose์์ ๊ฑฐ์ xml์์ ํ ์์๋ ๋ชจ๋ ๊ฒ๋ค์ ์ ์ํ๋ ๊ฐ์ฒด์ด๋ฉฐ, ๋ฐ๋ก ์ง์ ํ์ง์์ผ๋ฉด ๊ธฐ๋ณธ modifier๊ฐ ์ฌ์ฉ๋๋ค. ์ฌ์ฉํ ๋๋ ์ฒด์ด๋์ ์ด๋ค.
Modifier
.padding(16.dp)
.background(Color.Gray)
.clickable { /* ํด๋ฆญ ๋์ */ }
์ปดํฌ์ฆ์์๋ margin์ ์ง์ ํ์ง ์๊ณ padding๋ง ์ง์ ํ๋ค. margin์ ๋ช ์์ ์ผ๋ก ํ๋๊ฒ ์๋๋ผ offset์ผ๋ก ์์น ์กฐ์ ๋ง ํ๋ค๊ณ ์๊ฐํ๋ฉด ๋๊ฒ ๋ค. match_parent๊ฐ์ ๊ฑด `fillMaxWidth, fillMaxHeight, fillMaxSize` ๊ฐ์๊ฑธ๋ก ์ ๊ทผํ๋ฉด ๋๋ค. ํด๋ฆญ๋ฆฌ์ค๋๋ ์ฌ๊ธฐ์ ๋ฌ๋ฉด ๋๋ค.
๊ทผ๋ฐ xml๊ณผ ์์ฃผ ๋ค๋ฅธ์ ์ด ์กด์ฌํ๋ค. ์ฒด์ด๋ ์์๊ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ค๋ฅด๊ฒ ๋ง๋ ๋ค๋ ์ ์ด๋ค.
@Preview(showBackground = true)
@Composable
fun TestBox() {
Column {
Box(modifier = Modifier
.size(200.dp)
.padding(40.dp)
.background(Color.Red)) {
}
Box(modifier = Modifier.size(0.dp, 20.dp))
Box(modifier = Modifier
.padding(40.dp)
.size(200.dp)
.background(Color.Red)) {
}
}
}
์ฌ์ด์ฆ๋ฅผ ์ง์ ํ๊ณ ํจ๋ฉ์ ์ค๊ฒ๊ณผ, ํจ๋ฉ์ ๋จผ์ ์ฃผ๊ณ ์ฌ์ด์ฆ๋ฅผ ์ง์ ํ ๊ฒ์ ์์ ๋ค๋ฅด๋ค. ์ ์๋ ์ปจํ ์ธ ํฌ๊ธฐ๊ฐ 160, ํ์๋ 200์ด๋ค.
then์ ์ฌ์ฉํด์ ์กฐ๊ฑด๋ถ๋ก ๋ค๋ฅธ Modifier๋ฅผ ๋ถ์ด๋ ์์ ๋ ๊ฐ๋ฅํ๋ค.
@Preview(showBackground = true)
@Composable
fun TestBox() {
var isSelected by remember { mutableStateOf(false) }
Column {
Box(
modifier = Modifier
.size(200.dp)
.padding(40.dp)
.background(Color.Red)
) {
}
Box(modifier = Modifier.size(0.dp, 20.dp))
Box(
modifier = Modifier.padding(40.dp)
.size(200.dp)
.then(
if (isSelected) Modifier
.background(Color.Blue)
else Modifier
.background(Color.Red)
)
)
Button(onClick = { isSelected = !isSelected }) {
Text(if (isSelected) "์ ํ๋จ" else "์ ํ ์๋จ")
}
}
}
์ด๋ ๊ฒ ํ๋ฉด ๋ฒํผ์ ๋๋ฅผ๋, isSelected๊ฐ์ด ํ ๊ธ๋๋ฉด์ ํ๋จ Box์ Modifier๊ฐ ๊ฐ์ด ํ ๊ธ๋๋ค.
# Surface
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Surface(color = MaterialTheme.colorScheme.primary) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
}
์ปดํฌ์ฆ์์ Surface๋ ์ปดํฌ์ ๋ธ ์ปจํ ์ด๋ ์ค ํ๋๋ค. ๊ทผ๋ฐ ์ด์ Material Design์ ๊ณ๋ค์ธ ํํ๋ก, ์์์ ํด์ฃผ๋ ๊ธฐ๋ฅ์ด ๋ง์ ์ปดํฌ๋ํธ๋ค. ๋จธํฐ๋ฆฌ์ผ ๋์์ธ์์ ๋์จ ์ปดํฌ๋ํธ ๋ต๊ฒ, color์ primary๋ก ์ง์ ํ๋ฉด, colorScheme์ ์กด์ฌํ๋ primary ๋์ํ๋ onPrimary์๊น๋ก ์ปดํฌ๋ํธ ๋๋น๋ฅผ ์ด๋ค์ ๊ฐ๋ ์ฑ์ ๋ณด์ฅํ๋ค.
# ํธ์ด์คํ ๊ณผ ์ํ๊ด๋ฆฌ
์น ๊ฐ๋ฐ์์ ์ฒ์ ์ ํ ๋จ์ด์ธ๋ฐ, ์ปดํฌ์ฆ์๋ ๋ฑ์ฅํ๋ค.
Composable ํจ์์์ ์ฌ๋ฌ ๊ณณ์ ์ฐ์ด๋ ์ํ๋ ๊ณตํต ์์ํญ๋ชฉ์ ์์นํด์ผ๋๋ค. ์ด๊ฑธ ์ํ ํธ์ด์คํ ์ด๋ผ๊ณ ๋งํ๋ฉฐ ํ์ ์ปดํฌ์ ๋ธ์์ ์ํ ์ฌ์ฌ์ฉ์ด ๊ฐํธํด์ ์ข์ ๋ฐฉ๋ฒ์ด๋ค. Datasource๊ฐ ์ด๋ฐ ๊ณณ์ ์ํ๋ค.
flowchart LR
B(์ํ์ ๊ณต - MutableStateOf ๊ฐ์ฒด)
B --> D[A]
B --> E[B]
B --> F[C]
์ํ๊ฐ์ ์์์์๋ ๊ณต์ ํ๋ ๊ฒ ์๋๋ผ, ์ํ๊ฐ์ ์ก์ธ์ค ํด์ผ๋๋ ๊ณตํต ์์ ์์ ์ชฝ์ผ๋ก ์ํ๊ฐ์ ์ด๋์ํค๋ฉด ๋๋ค.
์ฆ ๋จ๋ฐฉํฅ์ฑ์ผ๋ก ์์ ์์๋ ํ์ ์์๋ก ์ํ๋ฅผ ์ ๋ฌํ๊ณ , ํ์ ์์๋ ๊ทธ๊ฑธ ๋ฐ์ ์ด๋ฒคํธ๋ฅผ ์์ ์์๋ก ์ ๊ณตํ๋, ๊ฑฐ์ ์น ๊ฐ๋ฐ์์์ ํธ์ด์คํ ๊ณผ ๋์ผํ ํํ๋ค. ๊ฐ๋จํ ์นด์ดํฐ ์ฝ๋๋ ๊ฐ์ด ๋ณด์.
@Composable
fun ParentComponent() {
var count by remember { mutableStateOf(0) }
HoistedCounter(
count = count,
onIncrement = { count++ }
)
}
์ต์์ ์ปดํฌ์ ๋ธ์ด๋ค. ์ฌ๊ธฐ์ count๋ฅผ ๊ด๋ฆฌํ๋ค.
@Composable
fun HoistedCounter(
count: Int,
onIncrement: () -> Unit
) {
Column {
Button(onClick = onIncrement) {
Text("์ฆ๊ฐ์ฆ๊ฐ")
}
Text("๊ฐ์: $count")
}
}
์ํ๋ฅผ Parentํํ ๋ฐ๊ณ , ์ํ๋ฅผ ๊ด๋ฆฌํ ๋์์ ๋๋ค๋ก ๋๊ฒจ ๋ฐ๋๋ค. ๊ทธ๋์ ์ด ํธ์ด์คํ ๋ฐ๋ ์ปดํฌ์ ๋ธ์์๋ ํด๋ฆญ์ด๋ฒคํธ๋ง ๊ด๋ฆฌํ๊ฒ ๋๋ค. ์ด๋๊ฐ ์ต์ํ๊ฒ ๋๊ปด์ง๋ค๋ฉด, recyclerview adapter๋ฅผ ์ฌ์ฉํ ๋ ํด๋ฆญ์ด๋ฒคํธ๋ฅผ ์ด๋ ๊ฒ ๋๊ธด ํํ๊ฐ ์์ด์๋ค. ํธ์ด์คํ ์ด ์ํ๊ด๋ฆฌ๋ฅผ ๋จ๋ฐฉํฅ์ผ๋ก ํด์ฃผ๊ธด ํ์ง๋ง, ๋๋ฌด depth๊ฐ ๊น์ด์ง๋ฉด ๋ฆฌ์ปดํฌ์ง์ ์ด ๋ฐ์ํ ์๋ ์์ด์ ํ์ํ ๋ถ๋ถ๋ง ํํธํํด์ ์ํ๋ฅผ ์ข ๋ ์์ ๋จ์๋ก ๊ด๋ฆฌํ๋ ๊ธฐ์ ์ด ํ์ํ๋ค.
๋ฆฌ์ปดํฌ์ง์ ์ ์ต์ํํ๊ธฐ ์ํด ์ด์ ์ ์ฌ์ฉํ์๋ remember๋ฅผ ์ ํํ ์๋ ์๊ณ , key๋ derivedStateOf๋ฅผ ์ฌ์ฉํด์ ์บ์ฑํด๋๋ ๋ฐฉ์์ผ๋ก ์ข ๋ ์ฑ๋ฅ์ ๋์ด์ฌ๋ฆด ์ ์๋ค. remeber๋ฅผ ์ฌ์ฉํ ๋ ์ฃผ์ํ ์ ์, ์ปดํฌ์ ๋ธ์ด ์ปดํฌ์ง์ ์ ์ ์ง๋๋ ๋์์๋ง ์๋ํ๋ค๋ ๊ฒ์ด๋ค. ๊ทธ๋์ ํ๋ฉดํ์ ๊ณผ ๊ฐ์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ๋ ์๊ฐ๋ค. ๊ทธ๋๋ rememberSaveable์ ์จ์ฃผ๋ฉด ๋๋๋ค.
val processedItems by remember(items) {
derivedStateOf { items.map { it.uppercase() } }
}
์ด๋ ๊ฒ ํ๋ฉด items์์ ๋ณ๊ฒฝ์ด ์์๋๋ง map ์์ ์ ์ํํ๋ค. ๋๋ค์ remember๋ฅผ ์ฌ์ฉํด์ ๋งค ๋ฆฌ์ปดํฌ์ง์ ๋ง๋ค ์๋ก์ด ๋๋ค๊ฐ ์์ฑ๋๋๊ฑธ ๋ง๋ ๋ฐฉํฅ์ผ๋ก ์ต์ ํ๋ฅผ ํ ์๋ ์๋ค.
key๊ฐ ์ค์ํ๋ฐ, ์ปดํฌ์ฆ๋ key ๊ฐ์ผ๋ก ์ด์ ์ปดํฌ์ง์ , ์ ์ปดํฌ์ง์ ์ ์ฐจ์ด๋ฅผ ๊ตฌ๋ถํ๋ค. ๊ทธ๋์ ๋์ผํ ํค๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉด ์ฌ์ฌ์ฉ๋๊ณ , ์๋๋ผ๋ฉด ์๋ก ์์ฑํ๋ค. ์๋ ์ฝ๋์ฒ๋ผ ๋ฆฌ์คํธ๊ฐ ์ฃผ์ด์ง ๋ ์ฌ์ฉํ๋ฉด ์ข๋ค. ๋ง์ฝ ๋งค๋ฒ ๋ฆฌ์คํธ ๋ด์ ์์๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์ฑ๋ฅ์ด ๋จ์ด์ง ์ ๋ ์๋ค. key๋ฅผ ์ฐ๋ฉด ๊ทธ๊ฒ๋ง ์ ๋ฐ์ดํธ ํ๋ฉด ๋ผ์ ๋ฆฌ์ปดํฌ์ง์ ์๋ ํจ์จ์ ์ธ ์์ ์ด ๊ฐ๋ฅํ๋ค.
@Composable
fun KeyTestList(items: List<String>) {
Column {
items.forEachIndexed { index, item ->
key(index) {
Text(item)
}
}
}
}
@Composable
fun MultipleKeysExample(items: List<Item>) {
Column {
items.forEach { item ->
key(item.id, item.category) {
ItemComponent(item)
}
}
}
}
ํค๋ฅผ ๋ช๊ฐ ์กฐํฉํด์ ๋ณตํฉํค๋ก ์ธ์๋ ์๋ค. ์ด๋ฐ ์ํ๊ด๋ฆฌ๋ ๋๊ท๋ชจ ๋ฆฌ์คํธ ๊ฐ์ ๊ณณ์์ ๋น์ ๋ฐํ๋๋ฐ, ์ง๊ธ๋ถํฐ ์์๋ณด์.
# `LazyColumn, LazyRow, LazyVerticalGrid...`
์ด ์น๊ตฌ๋ค์ ์๋ฒฝํ๊ฒ RecyclerView์ ์์ํธํ์ด๋ค. ์ฝ๋ ๋ช์ค๋ก ๊ธฐ์กด์ RecyclerViewAdapter๋ฅผ ์์ ํ ๋์ฒดํด์ค๋ค.
@Composable
private fun Greetings(
modifier: Modifier = Modifier,
names: List<String> = List(1000) { "$it" }
) {
LazyColumn(modifier = modifier.padding(vertical = 4.dp)) {
items(items = names) { name ->
Greeting(name = name)
}
}
}
์์ดํ 1000๊ฐ์ง๋ฆฌ ๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ๊ฐ ์์ฑ๋๋ค. RecycerView๋ ๋์๋ฐฉ์์ด ์ข ์ฐจ์ด๊ฐ ์๋๋ฐ, RecyclerView๊ฐ ์์ดํ ๋ทฐ๋ฅผ ๊ณ์ ์ฌํ์ฉํ๋ ๋ฐ๋ฉด Lazy ์๋ฆฌ์ฆ๋ค์ ๊ทธ๋ฅ ์ ์์ดํ ์ปดํฌ์ ๋ธ์ emitํ๋ ๋ฐฉ์์ด๋ค. ์์ดํ ์ ์ํ๋ ๊ณ ์ ํ๊ณ ์ถ๋ค๋ฉด ์ธ๋ฑ์ค์ ํด๋น ์์ดํ ์ ์ํ๊ฐ์ rememberSaveable๋ก ๋ง๋ค์ด์ ๊ด๋ฆฌํ๋ฉด ๋๋ค.
์๊น key๋ฅผ ์ฌ๊ธฐ์ ์ ์ฉํ๋ฉด ์๋์ฒ๋ผ ์ธ ์ ์๋ค.
@Composable
fun UserList(users: List<User>) {
LazyColumn {
items(users, key = { user -> user.id }) { user ->
UserItem(user)
}
}
}
๊ฐ ํญ๋ชฉ์ ๊ณ ์ ํค๋ฅผ user์ id๋ก ์ง์ ํด์ฃผ๋ ์ฝ๋๋ค.
@Composable
fun LazyColumnTest(items: List<String>) {
LazyColumn(
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
item {
Text("Header")
}
items(items) { item ->
Text(text = item)
}
itemsIndexed(items) { index, item ->
Text("Item at $index is $item")
}
item {
Text("Footer")
}
}
}
items์ ์์ดํ ๋ค์ด ๋ค์ด๊ฐ๊ณ , ๊ทธ์ ์ ์๋ item์ ํค๋, ๊ทธ ๋ค์์ ์๋ item์ ํธํฐ๋ค. ์ฌ์ง์ด items๋ฅผ ์ฌ๋ฌ๊ฐ ๋ฃ์ผ๋ฉด ์๋์ผ๋ก concat recycerview๋ค. itemsIndexed๋ฅผ ์ฌ์ฉํ๋ฉด ์ธ๋ฑ์ค๋ฒํธ์ ๊ฐ์ด ๋ค๋ฃฐ ์ ์์ด์ ์กฐ๊ธ ๋ ๊ฐ๋ฐ ์นํ์ ์ด๋ค.
์ข ๋ ์ถฉ๊ฒฉ์ ์ธ๊ฑด, LazyListState๋ฅผ ์จ์ list state๋ฅผ ๋ฐ๊ณ , ๊ทธ๊ฑธ ๊ธฐ์ค์ผ๋ก ํฐ๋ฌด๋ ์์ด ์ฝ๊ฒ ๋ฌดํ์คํฌ๋กค์ ๊ตฌํํ ์ ์๋ค๋ ์ ์ด๋ค.
val listState = rememberLazyListState()
LazyColumn(state = listState) {
...
}
LaunchedEffect(listState) {
snapshotFlow { listState.firstVisibleItemIndex }
.collect { index ->
if (index > items.size - 10) {
items += List(20) { "์ ์์ดํ
${items.size + it}" }
}
}
}
์ด๋ ๊ฒ ๋ฌดํ์คํฌ๋กค ๊ตฌํ์ด ๋๋ฌ๋ค. ์ง๊ธ์ ๊ทธ๋ฅ ํ๋์ฝ๋ฉ์ผ๋ก ์์ดํ ์ ๋๋ ค์คฌ์ง๋ง, ๋๋ค๋ก ์์ ์ปดํฌ์ ๋ธ์์ ์์ดํ ๋ค์ ๋ฐ์์ค๋ ํํ๊ฐ ์์ฃผ ์ฐ์ธ๋ค๊ณ ํ๋ค.
๋์์ด ๋๋ค๋ฉด ๋๊ธ์ด๋ ๊ณต๊ฐ ๋ฒํผ ํ ๋ฒ์ฉ ๋๋ฅด๊ณ ๊ฐ์ฃผ์ธ์!
'Android ๐ฅ๏ธ > Compose๐' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
@Immutable (0) | 2025.02.23 |
---|---|
SideEffect, LaunchedEffect, DisposableEffect ๋์์๋ฆฌ (1) | 2024.12.14 |
Composition & Recomposition ๋์ ์๋ฆฌ (1) | 2024.12.14 |