如何修复自定义按钮在 SwiftUI(IOS) 中的交互?

Posted

技术标签:

【中文标题】如何修复自定义按钮在 SwiftUI(IOS) 中的交互?【英文标题】:How do I fix a custom button has its interaction in SwiftUI(IOS)? 【发布时间】:2019-09-17 09:24:47 【问题描述】:

我在这样的 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,同时保持自定义按钮的交互

【问题讨论】:

【参考方案1】:

更新答案

基本上,您的第二个.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)
            
        
    

【讨论】:

以上是关于如何修复自定义按钮在 SwiftUI(IOS) 中的交互?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI - 在视图中包装 Button,以创建自定义按钮

自定义按钮样式 (SwiftUI) tvOS

如何在 SwiftUI Toggle 中使用自定义图像

SwiftUI打造一款美美哒自定义按压反馈按钮

SwiftUI打造一款美美哒自定义按压反馈按钮

SwiftUI 列表中的自定义按钮