@ObservedObject 更改后 SwiftUI 视图未更新

Posted

技术标签:

【中文标题】@ObservedObject 更改后 SwiftUI 视图未更新【英文标题】:SwiftUI View not updating after @ObservedObject is changed 【发布时间】:2020-07-02 10:53:08 【问题描述】:

预期功能:

    点按即可添加圈子 按“下一步”创建新的“框架” 将圆圈拖到新位置 按“返回”将圆圈恢复到之前的位置

问题: 如上图,在最后部分,当我点击“返回”时,圆圈停留在拖动位置,而不是按预期还原。

例如当我向 (0,0) 添加一个圆圈时,创建一个新框架,将圆圈拖到一个新位置 (10, 10) 并点击“返回”,控制台打印“Frame: 0, position (0, 0)"。当我点击下一步时,它会打印“Frame: 1, position (10,10)”。并再次点击“返回”打印 (0,0)。但 Circle 位置没有更新。

我尝试为 DraggableCircleModel 结构使用一个类,并在其位置上使用了@Published,但似乎效果不佳。

我在下面提供了我的课程以提供更多背景信息。这也是我第二次在这里发布问题,所以任何改进我的问题的建议都将不胜感激。非常感谢!

后退和下一步按钮

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 视图的相关部分

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 \($0.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)


【问题讨论】:

TL、DR...How to create a Minimal, Reproducible Example @Asperi 感谢您的评论。我刚刚更新了这个问题。如果还可以改进,请告诉我。 【参考方案1】:

解决了。问题在于DraggableCircle 视图的.position(...) 修饰符。以前,它只是反映 DraggableCircle 的状态,而不是基于底层的 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 的状态。

【讨论】:

以上是关于@ObservedObject 更改后 SwiftUI 视图未更新的主要内容,如果未能解决你的问题,请参考以下文章

Swift:尝试测试 ObservedObject 变量是不是为 nil 时的 EXC_BREAKPOINT

SwiftUI - 从 Swift 类启动的可观察对象不会更新 ContentView() 上的 @ObservedObject

在 Swift 中使用 @observable,我想使用计时器定期刷新 ObservedObject。我该怎么做呢?

ObservedObject 更改时的通知

嵌套 ObservedObject 中的更改不会更新 UI

ObservedObject 未触发视图重绘