swift - 有什么方法可以判断哪个状态更改导致在 SwiftUI 中重建 View ?

标签 swift animation swiftui gesture

我有一个 View 需要像 Accordion 一样工作,用户可以在其中拖动以打开/折叠它。我希望它在用户拖动时没有任何动画,但在他离开时有动画。因此,我想在我的 View 中使用两个状态变量(例如,height 和 tempHeight),但我只会在高度变量触发 View 重建过程时设置动画。

拖动时高度和 tempHeight 变化的动画看起来很奇怪,感觉有延迟。

描述我的问题的示例代码:

struct ContentView: View {
    @State var tempHeight: CGFloat = 200
    @State var height: CGFloat = 200
    var dragGesture: some Gesture {
        
        DragGesture(),
            .onChanged { value in
                
                tempHeight = min(400, max(200, height + value.translation.height))
            }
            .onEnded { value in
                
                height = tempHeight > 300 ? 400 : 200
                tempHeight = height
            }
    }
    
    var body: some View {
        VStack {
            Spacer()
                .frame(height: 100)
            Color.blue.frame(height: tempHeight)
                .animation(.easeIn)
                .gesture(dragGesture)
            Spacer()
        }
    }
}

我试图解决这个问题的方法是使用一个静态变量来跟踪最后发生的状态变化,而且它似乎可以工作。 我目前的解决方法:

enum StateChange {
    case height
    case tempHeight
    
    static var lastChangeBy: StateChange = .height
}

struct ContentView: View {
    @State var tempHeight: CGFloat = 200
    @State var height: CGFloat = 200
    
    var dragGesture: some Gesture {
        
        DragGesture()
            .onChanged { value in
                
                tempHeight = min(400, max(200, height + value.translation.height))
                StateChange.lastChangeBy = .tempHeight
            }
            .onEnded { value in
                
                height = tempHeight > 300 ? 400 : 200
                tempHeight = height
                StateChange.lastChangeBy = .height
                
            }
    }
    
    var body: some View {
        VStack {
            Spacer()
                .frame(height: 100)
            Color.blue.frame(height: tempHeight)
                .gesture(dragGesture)
                .animation(StateChange.lastChangeBy == .height ? .easeInOut : .none)
                .animation(.easeInOut)
            Spacer()
        }
    }
}

这对我来说就像是一个 hack。如果我有很多 @State 包装变量,它很快就会变得一团糟。是否有可能知道哪个状态变化会触发在体内构建 View ,以便我可以有条件地将动画应用于特定触发器或更好的编写方法。

最佳答案

你可以在修改器中明确指定哪些值变化会激事件画,比如

  Color.blue.frame(height: tempHeight)
        .gesture(dragGesture)
        .animation(.easeInOut, value: height)   // << here

关于swift - 有什么方法可以判断哪个状态更改导致在 SwiftUI 中重建 View ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63079017/

相关文章:

swift - 在搜索栏中弹出表格 View ,swift 2

ios - 如何使用 PDFKit 获取段落高度

c# - silverlight动画不工作

ios - SwiftUI 中的可选 @ObservableObject

swift - fatal error : Unexpectedly found nil while unwrapping an Optional value SwiftUI AnimatedImage

ios - View 以模态方式呈现而不是显示

ios - 如何在 swift 的 map View 上显示位置?我相信我的代码是最新的,但模拟器不显示位置或蓝点?

ios - 将图像与动画/效果一起拖/放到某个位置

css - 流畅的动画停止

ios - 添加自定义数组SwiftUI的元素