更改@ObservedObject 后SwiftUI 视图未更新
SwiftUI View not updating after @ObservedObject is changed
预期功能:
- 点击添加圈子
- 按“下一步”创建新的“框架”
- 将圆圈拖到新位置
- 按“后退”可将圆圈恢复到之前的位置
问题:
如上所示,在最后一部分,当我点击“后退”时,圆圈停留在拖动位置,而不是按预期恢复。
例如当我向 (0,0) 添加一个圆圈时,创建一个新框架,将圆圈拖到新位置 (10, 10) 并点击“返回”,控制台打印“Frame: 0, position ( 0,0)”。当我点击下一步时,它会打印“Frame: 1, position (10,10)”。并再次点击“返回”打印 (0,0)。但是Circle位置没有更新。
我试过对 DraggableCircleModel
结构使用 class 并在其位置上使用 @Published ,但似乎效果不佳。
我在下面提供了我的 classes 以提供更多背景信息。此外,这只是我第二次在这里发布问题,所以任何改进我的问题的建议都将不胜感激。非常感谢!
后退和下一步按钮
Button(action: {
self.viewModel.goTo(arrangementIndex: self.viewModel.currentIndex - 1)
}) { Text("Back") }
Button(action: {
self.viewModel.goTo(arrangementIndex: self.viewModel.currentIndex + 1)
}) { Text("Next")}
用于显示圆圈的视图:
struct DisplayView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
ZStack {
Rectangle()
.overlay(
TappableView { location in
self.viewModel.addCircle(at: location)
})
ForEach(self.viewModel.currentArrangement.circles, id: \.id) { circle in
return DraggableCircleView(viewModel: self.viewModel,
circleIndex: circle.circleIndex,
diameter: 50,
offset: circle.position)
}
}
}
}
DraggableCircle View的相关部分
struct DraggableCircleView: View {
init(viewModel: ViewModel, circleIndex: Int, diameter: CGFloat, offset: CGPoint) {
// Initialize
...
_viewState = /*State<CGSize>*/.init(initialValue: CGSize(width: offset.x, height: offset.y))
// **Debugging print statement**
print("\(self.viewModel.currentCircles.forEach{ print("Frame: \(self.viewModel.currentIndex), position \([=12=].position)") }) \n")
}
var body: some View {
let minimumLongPressDuration = 0.0
let longPressDrag = LongPressGesture(minimumDuration: minimumLongPressDuration)
.sequenced(before: DragGesture())
.updating($dragState) { value, state, transaction in
// Update circle position during drag
...
}
.onEnded { value in
guard case .second(true, let drag?) = value else { return }
// get updated position of circle after drag
...
self.viewModel.setPositionOfCircle(at: self.circleIndex, to: circlePosition)
}
return Circle()
// Styling omitted
...
.position(
x: viewState.width + dragState.translation.width,
y: viewState.height + dragState.translation.height
)
.gesture(longPressDrag)
}
解决了。问题在于 DraggableCircle
视图的 .position(...) 修饰符。以前,它仅反映 DraggableCircle 的 state,但并未根据底层 ViewModel 和 Model 进行更新。
将其更改为:
.position(
x: self.viewModel.currentCircles[circleIndex].position.x + dragState.translation.width,
y: self.viewModel.currentCircles[circleIndex].position.y + dragState.translation.height)
成功了。这是因为 DraggableCircle 的位置现在反映了底层 ViewModel 而不仅仅是 DraggableCircle 的状态。
预期功能:
- 点击添加圈子
- 按“下一步”创建新的“框架”
- 将圆圈拖到新位置
- 按“后退”可将圆圈恢复到之前的位置
问题: 如上所示,在最后一部分,当我点击“后退”时,圆圈停留在拖动位置,而不是按预期恢复。
例如当我向 (0,0) 添加一个圆圈时,创建一个新框架,将圆圈拖到新位置 (10, 10) 并点击“返回”,控制台打印“Frame: 0, position ( 0,0)”。当我点击下一步时,它会打印“Frame: 1, position (10,10)”。并再次点击“返回”打印 (0,0)。但是Circle位置没有更新。
我试过对 DraggableCircleModel
结构使用 class 并在其位置上使用 @Published ,但似乎效果不佳。
我在下面提供了我的 classes 以提供更多背景信息。此外,这只是我第二次在这里发布问题,所以任何改进我的问题的建议都将不胜感激。非常感谢!
后退和下一步按钮
Button(action: {
self.viewModel.goTo(arrangementIndex: self.viewModel.currentIndex - 1)
}) { Text("Back") }
Button(action: {
self.viewModel.goTo(arrangementIndex: self.viewModel.currentIndex + 1)
}) { Text("Next")}
用于显示圆圈的视图:
struct DisplayView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
ZStack {
Rectangle()
.overlay(
TappableView { location in
self.viewModel.addCircle(at: location)
})
ForEach(self.viewModel.currentArrangement.circles, id: \.id) { circle in
return DraggableCircleView(viewModel: self.viewModel,
circleIndex: circle.circleIndex,
diameter: 50,
offset: circle.position)
}
}
}
}
DraggableCircle View的相关部分
struct DraggableCircleView: View {
init(viewModel: ViewModel, circleIndex: Int, diameter: CGFloat, offset: CGPoint) {
// Initialize
...
_viewState = /*State<CGSize>*/.init(initialValue: CGSize(width: offset.x, height: offset.y))
// **Debugging print statement**
print("\(self.viewModel.currentCircles.forEach{ print("Frame: \(self.viewModel.currentIndex), position \([=12=].position)") }) \n")
}
var body: some View {
let minimumLongPressDuration = 0.0
let longPressDrag = LongPressGesture(minimumDuration: minimumLongPressDuration)
.sequenced(before: DragGesture())
.updating($dragState) { value, state, transaction in
// Update circle position during drag
...
}
.onEnded { value in
guard case .second(true, let drag?) = value else { return }
// get updated position of circle after drag
...
self.viewModel.setPositionOfCircle(at: self.circleIndex, to: circlePosition)
}
return Circle()
// Styling omitted
...
.position(
x: viewState.width + dragState.translation.width,
y: viewState.height + dragState.translation.height
)
.gesture(longPressDrag)
}
解决了。问题在于 DraggableCircle
视图的 .position(...) 修饰符。以前,它仅反映 DraggableCircle 的 state,但并未根据底层 ViewModel 和 Model 进行更新。
将其更改为:
.position(
x: self.viewModel.currentCircles[circleIndex].position.x + dragState.translation.width,
y: self.viewModel.currentCircles[circleIndex].position.y + dragState.translation.height)
成功了。这是因为 DraggableCircle 的位置现在反映了底层 ViewModel 而不仅仅是 DraggableCircle 的状态。