SwiftUI:输入无效时文本字段抖动动画

Posted

技术标签:

【中文标题】SwiftUI:输入无效时文本字段抖动动画【英文标题】:SwiftUI: Textfield shake animation when input is not valid 【发布时间】:2020-12-28 16:03:02 【问题描述】:

当用户按下“保存”按钮并且输入无效时,我想创建一个摇动动画。我的第一种方法是这样(为了简化,我删除了修饰符,而不是这种情况下的相关属性):

查看:

struct CreateDeckView: View 
    @StateObject var viewModel = CreateDeckViewModel()

    HStack 
        TextField("Enter title", text: $viewModel.title)
            .offset(x: viewModel.isValid ? 0 : 10)                 //
            .animation(Animation.default.repeatCount(5).speed(4))  // shake animation

         Button(action: 
                    viewModel.buttonPressed = true
                    viewModel.saveDeck()
                        self.presentationMode.wrappedValue.dismiss()
                    
                , label: 
                    Text("Save")
                )
         

视图模型:

class CreateDeckViewModel: ObservableObject

    @Published var title: String = ""
    @Published var buttonPressed = false

    var validTitle: Bool 
        buttonPressed && !(title.trimmingCharacters(in: .whitespacesAndNewlines) == "")
    

    public func saveDeck(completion: @escaping () -> ()) ... 

             

但是这个解决方案并没有真正起作用。当我第一次按下按钮时,没有任何反应。之后,当我更改文本字段时,它开始抖动。

【问题讨论】:

【参考方案1】:

使用GeometryEffect

struct ContentView: View 
        @StateObject var viewModel = CreateDeckViewModel()
        
        var body: some View       
            HStack 
                TextField("Enter title", text: $viewModel.title)
                    .modifier(ShakeEffect(shakes: viewModel.shouldShake ? 2 : 0)) //<- here
                    .animation(Animation.default.repeatCount(6).speed(3))
    
                Button(action: 
                    viewModel.saveDeck()
                        ...
                    
                , label: 
                    Text("Save")
                )
            
        
    
    
    //here
    struct ShakeEffect: GeometryEffect 
        func effectValue(size: CGSize) -> ProjectionTransform 
            return ProjectionTransform(CGAffineTransform(translationX: -30 * sin(position * 2 * .pi), y: 0))
        
        
        init(shakes: Int) 
            position = CGFloat(shakes)
        
        
        var position: CGFloat
        var animatableData: CGFloat 
            get  position 
            set  position = newValue 
        
    
    
    class CreateDeckViewModel: ObservableObject
        
        @Published var title: String = ""
        @Published var shouldShake = false
        
        var validTitle: Bool 
            !(title.trimmingCharacters(in: .whitespacesAndNewlines) == "")
        
        
        public func saveDeck(completion: @escaping () -> ())
            if !validTitle 
                shouldShake.toggle() //<- here (you can use PassThrough subject insteadof toggling.)
            
        
    

【讨论】:

谢谢!它有效,但老实说,我真的不明白为什么。切换部分让我感到困惑。 shouldShake 以 false 开头,然后我尝试使用空字段保存,shouldShake 正在更改为 true -> 触发了 shakeEffect(2)。但是,当我再次点击带有无效字段的按钮时,shouldShake 将变为 false。所以实际上不应该有震动效果,但它是?! @kirkyoyx talk.objc.io/episodes/S01E173-building-a-shake-animation

以上是关于SwiftUI:输入无效时文本字段抖动动画的主要内容,如果未能解决你的问题,请参考以下文章

从按钮操作中更改时未触发 SwiftUI 绑定

SwiftUI + Combine:如何将数据分配给带有动画的模型

SwiftUI:输入字段键盘动画导致选项卡视图中的其他视图动画

当输入无效时在 div 上添加抖动效果

清除按钮按下swiftui时如何自动上一个文本字段

当字段无效时,输入字段或帮助文本不会变成红色