ios - 如何修复自定义按钮在 SwiftUI(IOS) 中的交互?
问题描述
我像这样在 SwiftUi(ios) 中创建了一个自定义按钮,它有自己的交互,但是当我将它与其他两个动画一起使用时,按钮的交互被新的交互所取代
这是自定义按钮代码
import SwiftUI
public struct fillCircular: ButtonStyle {
var width: CGFloat
var height: CGFloat = 50
public func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.padding(.horizontal)
.frame(width: width, height: height)
.background(Capsule(style: .circular).fill(Color.primary))
.font(.titleChanga3)
.foregroundColor(Color.white)
.shadow(color: Color.primary
.opacity(configuration.isPressed ? 0.55 : 0.34),
radius: configuration.isPressed ? 1 : 4,
x: 0, y: configuration.isPressed ? 1 : 3)
.scaleEffect(CGSize(width: configuration.isPressed ? 0.99 : 1,
height: configuration.isPressed ? 0.99 : 1))
.animation(.spring())
}
}
这就是问题所在
struct Welcome: View {
@State var start: Bool = false
var body: some View {
GeometryReader { g in
Button(action: {}) {
Text("New Account")
}
.buttonStyle(fillCircular(width: g.size.width - (24 * 2)))
.offset(y: self.start ? 0 : 20)
.opacity(self.start ? 1 : 0)
.animation(Animation.easeOut(duration: 0.5).delay(0.4))
}
}
添加此方法后,自定义按钮(fillCircular)中的动画会发生变化
.animation(Animation.easeOut(duration: 0.5).delay(0.4))
如何进入Animation同时保持自定义按钮的交互
解决方案
更新的答案
基本上,您的第二个.animation()
电话会覆盖第一个电话。不要应用第二个动画,而是将你start = true
的withAnimation()
调用包装起来,如下所示:
struct WelcomeView: View {
@State var start: Bool = false
var body: some View {
VStack {
// This is just here to toggle start variable
Button("Toggle", action: {
withAnimation(Animation.easeOut(duration: 0.5).delay(0.4)) {
self.start.toggle()
}
})
GeometryReader { g in
Button(action: {}) {
Text("New Account")
}
.buttonStyle(fillCircular(width: g.size.width - (24 * 2)))
.offset(y: self.start ? 0 : 20)
.opacity(self.start ? 1 : 0)
}
}
}
}
然后easeOut
动画将仅在调用按钮的动作闭包时应用。
这个答案更简洁,但原版也适用于 Swift 5.1 / Xcode 11.0
原始答案
虽然它有点 hacky,但您可以在延迟后将start = true
动画设置为任何设置。.spring()
struct WelcomeView: View {
@State var start: Bool = false
@State var animation: Animation = Animation.easeOut(duration: 0.5).delay(0.4)
var body: some View {
VStack {
// This is just here to toggle start variable
Button("Toggle", action: {
if !self.start {
// Show button, and after combined delay + duration, set animation to .spring()
self.start.toggle()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) {
self.animation = .spring()
}
} else {
// Set animation to .easeOut(), then hide button
self.animation = Animation.easeOut(duration: 0.5).delay(0.4)
self.start.toggle()
}
})
GeometryReader { g in
Button(action: {}) {
Text("New Account")
}
.buttonStyle(fillCircular(width: g.size.width - (24 * 2)))
.offset(y: self.start ? 0 : 20)
.opacity(self.start ? 1 : 0)
.animation(self.animation)
}
}
}
}