如何为在 forEach 循环中单击的按钮设置动画?
How to animate a button getting clicked inside a forEach loop?
我正在尝试在用户点击按钮时为按钮设置动画。它在侧面偏移,使其看起来像是被按下的。
如果您查看图像,您应该明白为什么我想通过偏移来为其设置动画,因为我在按钮后面有一个偏移的背景,并且单击时按钮应该与该帧匹配。
目前,点击时按钮的动画如图所示,但所有按钮的动画都被按下,并且在点击发生后它们不会 return 到原始位置。
点击前的按钮
点击后的按钮
下面是按钮数组:
@State private var isClicked = false
let buttons: [[CalcButton]] = [
[.clear, .plusMinus, .percent, .divide],
[.seven, .eight, .nine, .multiply],
[.four, .five, .six, .minus],
[.one, .two, .three, .add],
[.zero, .doubleZero, .decimal, .equals]
]
ForEach(buttons, id: \.self) { row in
HStack(spacing: 20) {
ForEach(row, id: \.self) { item in
Button(action: {
withAnimation {
self.animation()
}
} , label: {
ZStack {
Rectangle()
.frame(width: buttonWidth(button: item), height: buttonHeight())
.foregroundColor(.backgroundColor)
.offset(x: 7.0, y: 7.0)
Rectangle()
.frame(width: buttonWidth(button: item), height: buttonHeight())
.foregroundColor(.white)
Text(item.rawValue)
.font(.custom("ChicagoFLF", size: 27))
.frame(width: buttonWidth(button: item), height: buttonHeight())
.foregroundColor(.backgroundColor)
.border(Color.backgroundColor, width: 4)
.offset(x: isClicked ? 7 : 0, y: isClicked ? 7 : 0)
}
})
}
}
.padding(.bottom, 10)
}
这是切换 isClicked 状态变量的函数
func animation() {
self.isClicked.toggle()
}
每个按钮都需要一个选择状态。所以最好创建一个自定义按钮。
这里是演示版代码。
自定义按钮视图
struct CustomButton: View {
var text: String
var action: () -> Void
@State private var isPressed = false
var body: some View {
Button(action: {
// Do something..
}, label: {
ZStack {
Rectangle()
.foregroundColor(.black)
.offset(x: 7.0, y: 7.0)
Rectangle()
.foregroundColor(.white)
Text(text)
.frame(width: 50, height: 50)
.foregroundColor(.black)
.border(Color.black, width: 4)
.offset(x: isPressed ? 7 : 0, y: isPressed ? 7 : 0)
}
})
.buttonStyle(PlainButtonStyle())
.simultaneousGesture(
DragGesture(minimumDistance: 0)
.onChanged({ _ in
// Comment this line if you want stay effect after clicked
isPressed = true
})
.onEnded({ _ in
isPressed = false
// // Uncomment below line and comment above line if you want stay effect after clicked
//isPressed.toggle()
action()
})
)
.frame(width: 50, height: 50)
}
}
用法:
struct DemoView: View {
var body: some View {
HStack(spacing: 10) {
ForEach(0..<10) { index in
CustomButton(text: index.description) {
print("Action")
}
}
}
}
}
如果你想在点击后保留你的效果。只需替换此代码部分即可。
.simultaneousGesture(
DragGesture(minimumDistance: 0)
.onChanged({ _ in
})
.onEnded({ _ in
isPressed.toggle()
action()
})
)
我正在尝试在用户点击按钮时为按钮设置动画。它在侧面偏移,使其看起来像是被按下的。
如果您查看图像,您应该明白为什么我想通过偏移来为其设置动画,因为我在按钮后面有一个偏移的背景,并且单击时按钮应该与该帧匹配。
目前,点击时按钮的动画如图所示,但所有按钮的动画都被按下,并且在点击发生后它们不会 return 到原始位置。
点击前的按钮
点击后的按钮
下面是按钮数组:
@State private var isClicked = false
let buttons: [[CalcButton]] = [
[.clear, .plusMinus, .percent, .divide],
[.seven, .eight, .nine, .multiply],
[.four, .five, .six, .minus],
[.one, .two, .three, .add],
[.zero, .doubleZero, .decimal, .equals]
]
ForEach(buttons, id: \.self) { row in
HStack(spacing: 20) {
ForEach(row, id: \.self) { item in
Button(action: {
withAnimation {
self.animation()
}
} , label: {
ZStack {
Rectangle()
.frame(width: buttonWidth(button: item), height: buttonHeight())
.foregroundColor(.backgroundColor)
.offset(x: 7.0, y: 7.0)
Rectangle()
.frame(width: buttonWidth(button: item), height: buttonHeight())
.foregroundColor(.white)
Text(item.rawValue)
.font(.custom("ChicagoFLF", size: 27))
.frame(width: buttonWidth(button: item), height: buttonHeight())
.foregroundColor(.backgroundColor)
.border(Color.backgroundColor, width: 4)
.offset(x: isClicked ? 7 : 0, y: isClicked ? 7 : 0)
}
})
}
}
.padding(.bottom, 10)
}
这是切换 isClicked 状态变量的函数
func animation() {
self.isClicked.toggle()
}
每个按钮都需要一个选择状态。所以最好创建一个自定义按钮。
这里是演示版代码。
自定义按钮视图
struct CustomButton: View {
var text: String
var action: () -> Void
@State private var isPressed = false
var body: some View {
Button(action: {
// Do something..
}, label: {
ZStack {
Rectangle()
.foregroundColor(.black)
.offset(x: 7.0, y: 7.0)
Rectangle()
.foregroundColor(.white)
Text(text)
.frame(width: 50, height: 50)
.foregroundColor(.black)
.border(Color.black, width: 4)
.offset(x: isPressed ? 7 : 0, y: isPressed ? 7 : 0)
}
})
.buttonStyle(PlainButtonStyle())
.simultaneousGesture(
DragGesture(minimumDistance: 0)
.onChanged({ _ in
// Comment this line if you want stay effect after clicked
isPressed = true
})
.onEnded({ _ in
isPressed = false
// // Uncomment below line and comment above line if you want stay effect after clicked
//isPressed.toggle()
action()
})
)
.frame(width: 50, height: 50)
}
}
用法:
struct DemoView: View {
var body: some View {
HStack(spacing: 10) {
ForEach(0..<10) { index in
CustomButton(text: index.description) {
print("Action")
}
}
}
}
}
如果你想在点击后保留你的效果。只需替换此代码部分即可。
.simultaneousGesture(
DragGesture(minimumDistance: 0)
.onChanged({ _ in
})
.onEnded({ _ in
isPressed.toggle()
action()
})
)