I followed a SwiftUI tutorial and have completed it and results working well, but as a challenge I wanted to try and convert the same code into MVVM structure but the final outputs are just not the same, and it's got to do something with the complication of getting both the index value and index itself within my forEach blocks. This is the non-MVVM format code:
struct Language:Identifiable{
var id:Int
var lang:String
}
struct ContentView_1:View{
@State private var languages : [Language] =
[ Language(id: 1, lang: "English"),
Language(id: 2, lang:"Spanish"),
Language(id: 3, lang:"German"),
Language(id: 4, lang:"Japanese"),
Language(id: 5, lang:"Chinese"),
Language(id: 6, lang:"Korean"),
Language(id: 7, lang:"Others")
]
@State private var completed : [Language] = []
@Namespace var nameSpace
var body: some View{
VStack{
VStack{
if !self.languages.isEmpty{
ForEach(self.languages){ language in
Text(language.lang)
.frame(width:100,height:100)
.background(Color.yellow)
.matchedGeometryEffect(id: language.id, in:self.nameSpace)
.onTapGesture{
self.completed.append(language)
self.languages.removeAll { (lang) -> Bool in
if lang.id == language.id{
return true
}else { return false }
}
}
}
}
}
HStack{
Text("Completed Languages")
.font(.title)
.fontWeight(.bold)
}
HStack{
ForEach(self.completed){ language in
Text(language.lang)
.frame(width:100,height:100)
.background(Color.green)
.matchedGeometryEffect(id: language.id, in:self.nameSpace)
.onTapGesture{
self.languages.append(language)
self.completed.removeAll { (lang) -> Bool in
if lang.id == language.id{
return true
}else { return false }
}
}
}
}
}
.animation(.easeOut)
}}
The above works fine as outlined in the tutorial I was following, but this is what I managed to put together as MVVM structure
struct LanguageModel:Identifiable{
var id:Int
var lang:String
}
class LanguageViewModel:ObservableObject{
@Published var languageModel:[ LanguageModel ] =
[LanguageModel(id: 1, lang: "English"),
LanguageModel(id: 2, lang:"Spanish"),
LanguageModel(id: 3, lang:"German"),
LanguageModel(id: 4, lang:"Japanese"),
LanguageModel(id: 5, lang:"Chinese"),
LanguageModel(id: 6, lang:"Korean"),
LanguageModel(id: 7, lang:"Others")
]
}
struct ContentView_2:View{
@ObservedObject var langData = LanguageViewModel()
@ObservedObject var langDataCompleted = LanguageViewModel()
@Namespace var nameSpace
var body: some View{
VStack{
VStack{
if !self.langData.languageModel.isEmpty{
ForEach(langData.languageModel.indices, id:\.self){ language in
Text(langData.languageModel[language].lang)
.frame(width:100,height:100)
.background(Color.yellow)
.matchedGeometryEffect(id: language, in: self.nameSpace)
.onTapGesture{
self.langDataCompleted.languageModel.append(langData.languageModel[language])
self.langData.languageModel.removeAll { (lang) -> Bool in
if lang.id == self.langData.languageModel[language].id{
return true
}else { return false }
}
}
}
}
HStack{
Text("Completed Languages")
.font(.title)
.fontWeight(.bold)
}
HStack{
ForEach(self.langDataCompleted.languageModel.indices ,id:\.self){ language2 in
Text(self.langDataCompleted.languageModel[language2].lang)
.frame(width:100,height:100)
.background(Color.green)
.matchedGeometryEffect(id: self.langDataCompleted.languageModel[language2].id, in: self.nameSpace)
.onTapGesture{
self.langData.languageModel.append(langDataCompleted.languageModel[language2])
self.langDataCompleted.languageModel.removeAll { (lang) -> Bool in
if lang.id == self.langDataCompleted.languageModel[language2].id{
return true
}else{ return false }
}
}
}
}
.padding(.all)
}
}
.animation(.easeOut)
.onAppear{
self.langDataCompleted.languageModel = []
}
}
}
I know there is a lot of code, but majority of it is just designing elements and SwiftUI modifiers. The exact issues include the languages not moving directly to the completed section after getting tapped on, the animations are completely off compared to the non-MVVM format, and there are odd gaps that show up in between the languages.