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
}
}
}
结果:
当按下视图时,我通过模型知道 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
}
}
}
结果: