每次SwiftUI中的Observed属性更改时动画显示视图

szqfcxe2  于 2023-02-03  发布在  Swift
关注(0)|答案(2)|浏览(172)

在下面的代码中,当你点击一个Image的时候,通过改变@State属性值,它会被动画化。我想做的是,每当@Published属性值改变的时候,动画化这个图像,这个属性位于ObservableObject中,并且是动态改变的。

使用Local @State属性 Package 器可以正常工作。

struct ContentView: View {
    @State private var scaleValue = 1.0
    @State private var isAnimating: Bool = true
        
    var body: some View {
        
        Image(systemName: "circle.fill")
            .scaleEffect(scaleValue)
            .font(.title)
            .foregroundColor(.green)
            .animation(.easeOut(duration: 0.3), value: isAnimating)
            .onTapGesture {
                self.isAnimating.toggle()
                self.scaleValue = 1.5
                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3){
                    self.scaleValue = 1.0
                }
            }
    }
}

正在使用Observed @Published属性 Package ,但不起作用。不确定将动画放在何处。

struct ContentView: View {
    @State private var scaleValue = 1.0       
    @StateObject private var contentVM = ContentViewModel()
    
    var body: some View {
        
        Image(systemName: "circle.fill")
            .scaleEffect(scaleValue)
            .font(.title)
            .foregroundColor(.green)
            .animation(.easeOut(duration: 0.3), value: contentVM.isAnimating)
           // not sure where to add the animation

    }
}

编辑:以下是工作溶液:

感谢@Fogmeister和@burnsi

class ContentViewModel: ObservableObject{
     @Published var isAnimatingImage = false 
}

struct ContentView2: View {
    @StateObject private var contentVM = ContentViewModel()
    
    var body: some View {

        @State private var scaleValue = 1.0
        
        Image(systemName: "circle.fill")
            .scaleEffect(scaleValue)
            .font(.title)
            .foregroundColor(.green)
            .animation(.easeOut(duration: 0.3), value: scaleValue)
            .onChange(of: contentVM.isAnimatingImage) {newValue in
                animateImage()
            }
    }

    func animateImage(){
        scaleValue = 1.5
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3){
            scaleValue = 1.0
        }
    }
}
r1zk6ea1

r1zk6ea11#

我认为这里的问题是.animation修饰符的错误用法。
你不需要用不同的布尔值来触发动画。如果动画是通过改变一个值来“驱动”的,在这个例子中是scaleValue,在修改器中使用那个值。
看看你的第一个例子中的动画。它没有完成。它缩放到所需的大小,然后收缩。但是它在收缩回来的同时跳到了动画的中间。
这将是第一个示例中的正确实现:

struct ContentView: View {
    @State private var scaleValue = 1.0
        
    var body: some View {
        
        Image(systemName: "circle.fill")
            .scaleEffect(scaleValue)
            .font(.title)
            .foregroundColor(.green)
            .animation(.easeOut(duration: 0.3), value: scaleValue)
            .onTapGesture {
                self.scaleValue = 1.5
                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3){
                    self.scaleValue = 1.0
                }
            }
    }
}

在第二个例子中

class ContentViewModel: ObservableObject{
    @Published var scaleValue = 1.0
}

struct ContentView2: View {
    @StateObject private var contentVM = ContentViewModel()
    
    var body: some View {
        
        Image(systemName: "circle.fill")
            .scaleEffect(contentVM.scaleValue)
            .font(.title)
            .foregroundColor(.green)
            .animation(.easeOut(duration: 0.3), value: contentVM.scaleValue)
            .onTapGesture {
                contentVM.scaleValue = 1.5
                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3){
                    contentVM.scaleValue = 1.0
                }
            }
    }
}
xdnvmnnf

xdnvmnnf2#

这就是为什么我们不应该在SwiftUI中使用视图模型对象,这也不是@StateObject的设计目的-它是为我们需要@State中的引用类型而设计的,而这里不是这样。如果你想将视图数据变量分组在一起,你可以将它们放在一个结构中,例如:

struct ContentViewConfig {
    var isAnimating = false
    var scaleValue = 1.0

    // mutating func someLogic() {}
}

// then in the View struct:
@State var config = ContentViewConfig()

相关问题