在 SwiftUI 中的 forEach 中获取索引和值
Posted
技术标签:
【中文标题】在 SwiftUI 中的 forEach 中获取索引和值【英文标题】:Getting both index and value within forEach in SwiftUI 【发布时间】:2020-07-19 21:41:04 【问题描述】:我按照 SwiftUI 教程完成了它并且结果运行良好,但作为一个挑战,我想尝试将相同的代码转换为 MVVM 结构,但最终输出不一样,它必须与在我的 forEach 块中获取索引值和索引本身的复杂性。 这是非MVVM格式代码:
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)
如我所关注的教程中所述,上述工作正常,但这是我设法将其组合为 MVVM 结构
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 = []
我知道有很多代码,但大部分只是设计元素和 SwiftUI 修饰符。 确切的问题包括语言在被点击后没有直接移动到已完成的部分,与非 MVVM 格式相比,动画完全关闭,并且语言之间出现了奇怪的差距。
【问题讨论】:
【参考方案1】:在 ForEach 循环中使用 .indices
可能会破坏动画。请改用.enumerated
。可以在这里找到一个很好的解释:How do you use .enumerated() with ForEach in SwiftUI?
注意:您不需要 两个 ObservableObjects。您可以拥有一个但有两个 @Published
属性:
class LanguageViewModel: ObservableObject
@Published var languages: [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")
]
@Published var completedLanguages: [LanguageModel] = []
【讨论】:
不幸的是,它没有完成这项工作。该应用程序管理运行,但所有问题仍然存在。【参考方案2】:经验法则:
索引在突变时失效。
当涉及到追加/删除时,您不应该使用索引。
而且不值得尝试。
不使用索引,看看效果如何。
【讨论】:
以上是关于在 SwiftUI 中的 forEach 中获取索引和值的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI - 在 ForEach 中获取 TextField 数组
使用 SwiftUI ForEach 从 NSOrderedSet 获取字符串值