swiftui - 使用 ForEach 创建视图,但如何让 onTapGesture 立即更新?
问题描述
这段代码的工作方式与我想要的随机播放动画完全一样,除了当用户点击一个矩形(在随机播放之间)时,onTapGesture 中的颜色变化在下一次随机播放之前不会更新。我需要看到它被点击时的颜色变化。我已经尝试了几种不同的方法来做到这一点,每种方法都给我带来了死胡同。是不是我的数据模型偏离了轨道?有没有更好的方法来实现这一点?提前致谢!我对 SwiftUI 还是很陌生,所以期待从中学习。
import SwiftUI
class EachSpace: ObservableObject, Identifiable {
let id = UUID()
@Published var num: Int
@Published var tapped: Bool
@Published var highlight: Bool
init(number: Int) {
num = number
tapped = false
highlight = false
}
}
class Column: ObservableObject, Identifiable {
@Published var spaces = [EachSpace]()
@Published var space0: EachSpace
@Published var space1: EachSpace
@Published var space2: EachSpace
@Published var space3: EachSpace
@Published var space4: EachSpace
let id = UUID()
init(low: Int, high: Int) {
var randIntArray = [Int]()
var tempNum = 0
var found = false
for _ in 0..<5 {
repeat {
tempNum = Int.random(in: low...high)
if (randIntArray.firstIndex(where: {$0 == tempNum}) != nil) {
found = true
} else { found = false }
} while found
randIntArray.append(tempNum)
}
space0 = EachSpace(number: randIntArray[0])
space1 = EachSpace(number: randIntArray[1])
space2 = EachSpace(number: randIntArray[2])
space3 = EachSpace(number: randIntArray[3])
space4 = EachSpace(number: randIntArray[4])
spaces.append(space0)
spaces.append(space1)
spaces.append(space2)
spaces.append(space3)
spaces.append(space4)
}
}
class Card: ObservableObject {
@Published var columns = [Column]()
@Published var columnX = Column(low: 1, high: 25)
@Published var columnY = Column(low: 26, high: 50)
@Published var columnZ = Column(low: 51, high: 75)
init() {
columns.append(columnX)
columns.append(columnY)
columns.append(columnZ)
}
}
struct ContentView: View {
@State private var rotate = false
@ObservedObject var card = Card()
var body: some View {
VStack {
HStack {
ForEach(card.columns) { col in
VStack {
ForEach(col.spaces) { space in
Text("\(String(space.num))")
.font(.system(size: 20))
.fontWeight(.black)
.frame(width: 40, height: 40, alignment: .center)
.background(space.tapped ? Color.blue : Color.red)
.clipShape(Rectangle())
.foregroundColor(.white)
.padding(10)
.rotationEffect(Angle(degrees: rotate ? 0 : 360))
.onTapGesture {
space.tapped.toggle()
}
}
}
}
}
Button(action: {
withAnimation(Animation.linear(duration: 1.0)) {
self.rotate.toggle()
self.card.columnX.spaces.shuffle()
self.card.columnY.spaces.shuffle()
self.card.columnZ.spaces.shuffle()
}
})
{
Text("Shuffle")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
解决方案
原因是@ObservedObject
/ObservableObject
不会跨越嵌套的可观察对象 - 即EachSpace.tapped
观察根Card
对象的视图不会观察到变化。
最简单的解决方法是将最里面的Text
视图移动到一个单独的视图中,该视图将EachSpace
直接观察每个对象:
struct SpaceView: View {
@ObservedObject var space: EachSpace
var body: some View {
Text("\(String(space.num))")
.font(.system(size: 20))
.fontWeight(.black)
.frame(width: 40, height: 40, alignment: .center)
.background(space.tapped ? Color.blue : Color.red)
.clipShape(Rectangle())
.foregroundColor(.white)
.padding(10)
.rotationEffect(Angle(degrees: rotate ? 0 : 360))
.onTapGesture {
space.tapped.toggle()
}
}
}
并将其中的更改ForEach
为ContentView
:
ForEach(col.spaces) { space in
SpaceView(space: space)
}
推荐阅读
- reactjs - React - 通过 useContext 在组件中使用状态
- firebase - 从 Flutter Web 应用程序发送 Firebase 存储授权作为 url 参数
- c# - 即使列表为空,C# 列表也始终显示 1 个元素
- gherkin - 将自定义(结构化)元数据添加到场景
- flutter - Flutter audioplayers plugin - 如何从此链接播放在线广播?
- static-analysis - 静态分析错误地报告越界访问
- google-cloud-platform - 如何从另一台服务器重新启动 GCP 上的虚拟机?
- python - 如何使用 python 将列表的一些值放入字典中?
- xamarin - 如何通过 Xamarin 中的配置设置默认代理?
- python - Python,安装的脚本无法将命名空间误认为模块