androidx.lifecycle:lifecycle-viewmodel 2.8.0 버전이 정상적으로 출시되었습니다.
2.8.0 부터 정식적으로 Kotlin MutliPlatform을 지원합니다.
간단하게 사용해봅시다.!
신규 프로젝트를 하나 만들어 주고 종속성을 추가해줍니다.
commonMain.dependencies {
implementation(libs.androidx.lifecycle.viewmodel)
}
androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel", version = "2.8.0" }
CommonMain에 다음과 같이 작성하였습니다.
class MainViewModel : ViewModel() {
private var _showSplash = MutableStateFlow(true)
val showSplash: StateFlow<Boolean>
get() = _showSplash
fun hideSplash(withDelay: Long) {
viewModelScope.launch {
delay(withDelay)
_showSplash.value = false
print("스플래쉬 종료")
}
}
}
4초뒤에 허접한 스플래쉬가 사라지도록 해보겠습니다..
class MainActivity : ComponentActivity() {
private val mainViewModel : MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApplicationTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
val showSplash by mainViewModel.showSplash.collectAsState()
Box {
GreetingView(Greeting().greet())
if (showSplash) {
LaunchedEffect(true) {
mainViewModel.hideSplash(4000L)
}
Column(
modifier = Modifier
.fillMaxSize()
.background(androidx.compose.ui.graphics.Color.White),
verticalArrangement = Arrangement.Center
) {
Text(text = "허접한 스플래쉬")
}
}
}
}
}
}
}
}
잘 작동하는군요
이번에는 IOS에서 해보겠습니다.
struct ContentView: View {
let greet = Greeting().greet()
let mainViewModel : MainViewModel = MainViewModel()
@State private var showSplash :Bool = true
var body: some View {
ZStack {
Text(greet)
if(showSplash) {
VStack{
Text("허접한 스플래쉬")
.frame(maxWidth: .infinity,maxHeight: .infinity,alignment: .center)
}
.frame(maxWidth: .infinity,maxHeight: .infinity)
.background(.white)
.onAppear{
mainViewModel.hideSplash(withDelay: Int64(4000))
}
}
}
.onAppear{
mainViewModel.showSplash.collect(
collector: Collector<Bool> { value in
showSplash = value
}
) { error in
}
}
}
}
class Collector<T> : Kotlinx_coroutines_coreFlowCollector {
let callback:(T) -> Void
init(callback: @escaping (T) -> Void) {
self.callback = callback
}
func emit(value: Any?, completionHandler: @escaping (Error?) -> Void) {
callback(value as! T)
completionHandler(nil)
}
}
잘 작동하는 군요
다만 StateFlow를 바로 못쓰니 개선이좀 필요해 보입니다.. 매번 모든뷰에 저렇게 작업 해 주기는 힘들자나요~
좀 개선해봅시다.
기존에 작성된 MainViewModel을 BaseViewModel로 바꾸고 open으로 바꾸어 상속 받을수 있게 해봅시다.
open class BaseViewModel : ViewModel() {
...
}
아래와 같이 수정하면 동일한 코드가 됩니다.
class MainViewModel : BaseViewModel()
아래와 같이 수정했습니다.
class MainViewModel : ObservableObject {
private let base : BaseViewModel = BaseViewModel()
@Published var showSplash :Bool = true
init() {
base.showSplash.collect(
collector: Collector<Bool> { value in
self.showSplash = value
}
) { error in
}
}
func hideSplash(withDelay: Int64) {
base.hideSplash(withDelay: withDelay)
}
}
struct ContentView: View {
let greet = Greeting().greet()
@StateObject var mainViewModel : MainViewModel = MainViewModel()
var body: some View {
ZStack {
Text(greet)
if(mainViewModel.showSplash) {
VStack{
Text("허접한 스플래쉬")
.frame(maxWidth: .infinity,maxHeight: .infinity,alignment: .center)
}
.frame(maxWidth: .infinity,maxHeight: .infinity)
.background(.white)
.onAppear{
mainViewModel.hideSplash(withDelay: 4000)
}
}
}
}
}
똑같이 작동하지만 viewmodel이 완전히 분리되었습니다.
굳