SwiftUI:打开带有动态内容的模式表仅在第一次尝试时失败
Posted
技术标签:
【中文标题】SwiftUI:打开带有动态内容的模式表仅在第一次尝试时失败【英文标题】:SwiftUI: Opening a modal sheet with dynamic content fails only on first attempt 【发布时间】:2020-08-24 23:57:38 【问题描述】:目标是将动态内容传递到单个模式中,就好像它是一个详细视图:
import SwiftUI
struct Item
let number: String
let id = UUID()
class ItemSet: ObservableObject
@Published var collection: [Item]
init()
self.collection = []
for index in 1...100
self.collection.append(Item(number: "\(index)"))
struct ContentView: View
@ObservedObject var items: ItemSet
@State private var selectedItem: Item?
@State private var showingFull = false
init()
self.items = ItemSet()
self.selectedItem = nil
var columns = [
GridItem(.adaptive(minimum: 150), spacing: 5.0)
]
var body: some View
ScrollView
LazyVGrid(columns: columns)
ForEach(items.collection, id: \.id) item in
Text(item.number)
.frame(height: 100)
.onTapGesture
self.selectedItem = item
self.showingFull = true
.sheet(isPresented: $showingFull)
if let item = selectedItem
Text(item.number)
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
由于某种原因,第一次点击单元格时,模态框是空的,就好像在呈现模态框内容之前状态没有更新,但之后的任何时间都按预期工作。我是否遗漏了一些明显的东西,还是应该提交雷达?
【问题讨论】:
对我来说唯一可行的解决方案是将selectedItem
从视图中的@State
移动到模型中的@Published
,并将.sheet
移出ForEach
.
这能回答你的问题吗? SwiftUI: show different sheet items conditionally
【参考方案1】:
这是多表冲突,因为您将同一张表附加到 ForEach
中的每个单元格并绑定到单个状态,因此单击它们会立即激活。解决方法是将工作表移出ForEach
这是一个更正的部分。使用 Xcode 12 / ios 14 测试
var body: some View
ScrollView
LazyVGrid(columns: columns)
ForEach(items.collection, id: \.id) item in
Text(item.number)
.frame(height: 100)
.onTapGesture
self.selectedItem = item
self.showingFull = true
.sheet(isPresented: $showingFull) // << here !!
if let item = selectedItem
Text(item.number)
【讨论】:
啊,是的,将工作表放入 ForEach 是一个非常愚蠢的错误。但是,我刚刚尝试了您的确切正文代码,得到了相同的结果:第一个模态中没有任何内容,然后一切正常。我在 Xcode beta 5 上,所以也许这只是一个回归。我现在要归档雷达... 在模拟器或真机上试用,预览可能会失败。 在物理 iPhone11,6、动态 SwiftUI 预览和模拟 iPhone 11 上试用;都产生了相同的描述结果。 beta 6 的结果相同;反馈归档为 FB8531587 有什么解决办法吗?【参考方案2】:我发现的一个可能的解决方案是将工作表和状态移动为它们自己的结构:
struct ContentView: View
@ObservedObject var items: ItemSet
init()
self.items = ItemSet()
var columns = [
GridItem(.adaptive(minimum: 150), spacing: 5.0)
]
var body: some View
ScrollView
LazyVGrid(columns: columns)
ForEach(items.collection, id: \.id) item in
TextItem(item: item)
struct TextItem: View
let item: Item
@State private var showingFull = false
var body: some View
Text(item.number)
.frame(height: 100)
.onTapGesture
self.showingFull = true
.sheet(isPresented: $showingFull)
Text(item.number)
我不知道这个解决方案在正确的 SwiftUI 方面有多“正确”,但在更复杂和繁重的布局中使用时,我没有注意到任何性能问题。
【讨论】:
这确实有帮助。【参考方案3】:遇到同样的问题并通过切换到sheet(item)
并删除布尔检查以显示工作表来解决它
struct TextItem: View
@State let item: Item
var body: some View
Text(item.number)
.frame(height: 100)
.onTapGesture
self.showingFull = true
.sheet($item)
Text($0.number)
【讨论】:
以上是关于SwiftUI:打开带有动态内容的模式表仅在第一次尝试时失败的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI 模态演示仅在 navigationBarItems 中有效
带有表单的 SwiftUI 模态表:设备旋转后左/右填充错误