SwiftUI 如何临时为视图颜色的 foregroundColor 设置动画?

SwiftUI how do I temporarily animate a view color's foregroundColor?

当按下视图时,我通过模型知道 button.isSelected。如何为视图的前景色设置动画,类似于 IOS 计算器按钮按下动画?

类似于:

白色 -> 灰色 -> 白色

struct ButtonView: View {
    let button: ViewModel.Button

    
    var body: some View {
        let shape = Rectangle()
        ZStack {
            shape.fill().foregroundColor(button.isSelected ? Color.gray : Color.white)
                .animation(Animation.linear(duration: 0.01))
            .border(Color.black, width: 0.33)
            Text(button.content)
            .font(Font.system(size:32))
            
        }
    }
}

我认为有很多方法可以做到这一点。 其中,我会写一个使用DispatchQueue.main.asyncAfter()

的例子
struct ContentView: View {
    @State private var isSelected: Bool = false
    
    var body: some View {
        VStack {
            Button {
                isSelected = true
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.2 ) {
                    // To change the time, change 0.2 seconds above
                    isSelected = false
                }
            } label: {
                Text("Button")
                    .foregroundColor(isSelected ? Color.red : Color.blue)
            }
        }
    }
}

虽然 DispatchQueue.main.asyncAfter() 会像 一样工作,请注意计算器应用程序如何不使用设置的延迟。相反,它会在手指按下时改变颜色,然后在松开时恢复原状。

所以,您可能想要 ButtonStyle

struct ContentView: View {
    var body: some View {
        ButtonView()
    }
}

struct CalculatorButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .padding() /// no need to use `shape` + `ZStack`, normal padding is ok
            .background(configuration.isPressed ? Color.gray : Color.white) /// use `isPressed` to determine if button is currently pressed or not
            .animation(Animation.linear(duration: 0.01))
            .cornerRadius(10)
    }
}

struct ButtonView: View {
    var body: some View {
        ZStack {
            Color.black /// for testing purposes (see the button better)
            
            Button {} label: {
                Text("Button")
                    .font(.system(size: 32))
            }
            .buttonStyle(CalculatorButtonStyle()) /// apply the style
        }
    }
}

结果: