SwiftUI ForEach 视图第一次没有更新
Posted
技术标签:
【中文标题】SwiftUI ForEach 视图第一次没有更新【英文标题】:SwiftUI ForEach views not updating for the first time 【发布时间】:2019-11-26 16:22:38 【问题描述】:我正在尝试使用 ForEach 填充一组视图。我使用 Alamofire 获取数据并设置 @State 属性以触发更新。不幸的是,仅当我切换屏幕(使用 TabBar)或转到主屏幕并重新打开应用程序时才会显示更新。
以下是我用过的代码sn-p:
@State var posts : [Post]
var body: some View
ScrollView
VStack(alignment: .leading, spacing: 0)
ForEach(posts, id: \.id) preview in
PreviewDetailView(preview: preview).background(Color(.white).cornerRadius(30))
.onAppear(perform: fetchPosts())
显然,PreviewDetailView
(我在其中显示 API 响应数据)被触发,但视图没有更新。
【问题讨论】:
你看到了吗:github.com/onmyway133/blog/issues/468? 不,但我会试试这个。谢谢!。虽然我也尝试过不使用 onAppear 并使用 @ObservableObject 和 ObservedObject。 【参考方案1】:原因是当您在ScrollView
中使用stack
或ForEach
时,您必须设置帧限制来初始化视图设置,如下所示。
ScrollView
VStack(alignment: .leading, spacing: 0)
ForEach(self.posts, id: \.id) preview in
PreviewDetailView(preview: preview)
.background(Color(.red).cornerRadius(30))
.frame(maxWidth: .infinity) // Here
.onAppear
self.fetchPosts()
【讨论】:
还是没有运气! forEach 子视图的 onAppear 确实会被调用,但不会显示,除非我将应用切换到后台,然后再切换回前台。 它对我有用。我认为如果没有初始视图,原因在于滚动视图,滚动视图不确定未来的尺寸。您可以在滚动视图中放置一些支架或加载指示器。当数据准备好时,它将更新视图。你是如何更新你的数据的?现在我确信这是主要原因! 好吧,我刚刚更新了您可以在我的代码 sn-p 中找到的“posts”属性。只需执行 self.posts = posts 即可更新 API 响应。无论如何,您添加占位符视图的观点是有道理的,我会尝试一下! 即使我放置了一个占位符,ScrollView 也会在未来将其自身限制在这些维度上。因此,如果我的 ForEach 有更大的视图列表,其中一些将不会显示。还有一些进展! 可能是性能问题。只需使用简单数据而不是您的数据来将问题与 Ui 和数据更新隔离开来【参考方案2】:我想,你必须检查“posts”对象是否为空;
if !self.posts.isEmpty
ForEach(self.posts, id: \.id) preview in
PreviewDetailView(preview: preview)
.background(Color(.red).cornerRadius(30))
【讨论】:
我认为这个答案对了一半;检查forEach
中使用的数据是否已经被提取确实是可行的方法,但if
必须早一点使用;在 ScrollView 之前,因此仅当存在数据时才会附加 scrollView。因为就像@Asperi 提到的那样 - 这里的 scrollView 是一个真正的问题。有趣的是,在 ios14 上运行完全相同的代码时,这似乎得到了解决。【参考方案3】:
我可以猜到您的 posts
最初是空数组...这是一个(不知道功能或错误)与空容器的独立 ForEach 初始化。顺便说一句,在这种情况下,列出一切都可以。既不是@State
,也不是@ObservedObject
,也不是onAppear
,也不是自定义发布者的影响或帮助。只需在 ForEach 启动时清空容器即可。
解决方法:在容器中使用一些初始存根 Post,可以在视图构建器中进行有条件地检查而不显示
或者使用 List 代替 ScrollView/VStack/ForEach。
更新:我的错...当我写下这个最新的短语时,我有一个想法,我会在这样的组合中使用它ScrollView/VStack/ForEach
...简而言之,问题在 ScrollView 中。
【讨论】:
【参考方案4】:我的解决方案是像这样为 VStack 设置 minHeight:
ScrollView
VStack(alignment: .leading, spacing: 0)
ForEach(self.posts, id: \.id) preview in
PreviewDetailView(preview: preview)
.background(Color(.red).cornerRadius(30))
.frame(minHeight: <some_reasonable_Float_value, minWidth: <same_here>)
就像一些海报提到的那样,ScrollView
提前不知道要渲染的项目的尺寸是多少,所以它会自行折叠。
【讨论】:
以上是关于SwiftUI ForEach 视图第一次没有更新的主要内容,如果未能解决你的问题,请参考以下文章
使用 ForEach 插入的 SwiftUI 视图未随动画更新