👉🏻 프로젝트 명이 parentchildview인 경우 입니다.
If the project name is parentchildview.
👉🏻viewModel():
Composable에서 ViewModel을 가져오거나 생성하고 재사용하도록 해줍니다.
SwiftUI에서 @StateObject , @ObservedObject와 유사한 기능을 수행합니다.
Allows you to import, create, and reuse ViewModels from Composable. It performs similar functions to @StateObject and @ObservedObject in SwiftUI.
Parent 뷰에서 실행하고 Child 뷰에서는 실행하지 않습니다.
It runs in the Parent view and not in the Child view.
좀 더 자세히 설명하면
To explain a bit more
val viewModel: CounterViewModel = viewModel()
위의 코드에서 viewModel()함수가 호출되면 Composable에서 viewModel<CounterViewModel>()가 실행됩니다.
In the above code, when the viewModel() function is called, viewModel() is executed in Composable.
이 때 ViewModelStore에 CounterViewModel인스턴스가 있는지 확인하고 있으면 반환하고 없으면 인스턴스를 생성해서 반환합니다.
At this time, check if there is a CounterViewModel instance in ViewModelStore, and if so, return it. If not, create an instance and return it.
ViewModelStore는 Compose나 Android ViewModel(Architecture Components ViewModel)을 사용할 때 만 관련 인스턴스를 저장합니다.
ViewModelStore only stores relevant instances when using Compose or Android ViewModel (Architecture Components ViewModel).
결론은 viewModel에는 CounterViewModel 인스턴스 참조가 들어 있습니다.
The bottom line is that viewModel contains a reference to a CounterViewModel instance.
👉🏻 아래의 코드는 CounterViewModel인스턴스의 count변수에 collectAsState()를 적용하라는 의미입니다.
The code below means to apply collectAsState() to the count variable of the CounterViewModel instance.
collectAsState()는 CounterViewModel 내부의 count(StateFlow)를 Compose 상태로 변환하여 UI가 자동으로 관찰하게 만든다는 의미입니다.
collectAsState() means that count(StateFlow) inside CounterViewModel will be converted to a Compose state so that the UI can automatically observe it.
관찰이란 단순히 읽는 것뿐만 아니라 “값이 바뀌었을 때 UI가 자동으로 다시 그려지도록 연결” 하는 의미까지 포함합니다.
Observation doesn’t just mean reading, it also means “connecting the UI so that it automatically redraws when a value changes.”
val count by viewModel.count.collectAsState()
✔️MainActivity.ky
package com.freelifemakers.parentchildview
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.freelifemakers.parentchildview.ui.theme.ParentChildViewTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
ParentChildViewTheme {
Scaffold(
modifier = Modifier.fillMaxSize()
) { innerPadding ->
// ParentView 호출 / Parent View Call
ParentView(
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
}
// 기존 코드 / Exsisting code
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
ParentChildViewTheme {
Greeting("Android")
}
}
✔️ ParentView.kt
package com.freelifemakers.parentchildview
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun ParentView(modifier: Modifier = Modifier) {
val viewModel: CounterViewModel = viewModel()
val count by viewModel.count.collectAsState()
Column(
modifier = modifier.padding(20.dp)
) {
Text("Parent View Count: $count", style = MaterialTheme.typography.headlineMedium)
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = { viewModel.increase() }) {
Text("Increase")
}
Spacer(modifier = Modifier.height(16.dp))
// 지식 뷰 호출 / Child view call
ChildView(viewModel)
}
}
✔️ ChildView.kt
package com.freelifemakers.parentchildview
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun ChildView(viewModel: CounterViewModel) {
val count by viewModel.count.collectAsState()
Column(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
) {
Text(
"Child View Count: $count",
style = MaterialTheme.typography.titleMedium
)
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = { viewModel.increase() }) {
Text("Increase from Child")
}
}
}
✔️ ViewModel.kt
package com.freelifemakers.parentchildview
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
class CounterViewModel : ViewModel() {
private val _count = MutableStateFlow(0)
val count: StateFlow<Int> = _count.asStateFlow()
fun increase() {
_count.value += 1
}
}
✔️ 스크린샷 / ScreenShot