【问题标题】:Shake Animation for UITextField/UIView in Swift在 Swift 中为 UITextField/UIView 摇动动画
【发布时间】:2015-03-15 05:45:53
【问题描述】:

我试图弄清楚当用户将文本字段留空时如何使文本字段在按钮按下时抖动。

我目前正在运行以下代码:

if self.subTotalAmountData.text == "" {

    let alertController = UIAlertController(title: "Title", message:
        "What is the Sub-Total!", preferredStyle: UIAlertControllerStyle.Alert)
    alertController.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default,handler: nil))

    self.presentViewController(alertController, animated: true, completion: nil)

} else {

}

但我认为将文本字段摇动作为警报会更具吸引力。

我找不到任何东西来为文本字段设置动画。

有什么想法吗?

谢谢!

【问题讨论】:

  • 你做了什么来尝试为文本字段设置动画?
  • 我不知道从哪里开始。对我来说没有任何意义,而且我找不到任何教程,即使是我可以采用的最轻微的变化。我已经尝试过 animateWithDuration UIViewAnimationOptions.Transition 但代码总是错误地说明我如何理解它。
  • Google for iPhone 动画教程。 Ray Wanderlich 的文章通常很好读。
  • 谢谢,我会尽力阅读并理解!

标签: ios swift uitextfield


【解决方案1】:

您可以更改durationrepeatCount 并对其进行调整。这就是我在我的代码中使用的。改变fromValuetoValue 将改变摇晃中移动的距离。

let animation = CABasicAnimation(keyPath: "position")
animation.duration = 0.07
animation.repeatCount = 4
animation.autoreverses = true
animation.fromValue = NSValue(cgPoint: CGPoint(x: viewToShake.center.x - 10, y: viewToShake.center.y))
animation.toValue = NSValue(cgPoint: CGPoint(x: viewToShake.center.x + 10, y: viewToShake.center.y))

viewToShake.layer.add(animation, forKey: "position")

【讨论】:

  • 不知道为什么,但我得到了这个异常:2015-05-17 19:43:00.744 pdfdistributor[19908:2303862] -[pdfdistributor.ViewController mLoginBT:]: unrecognized selector sent to instance 0x7fca90d17e00 2015-05-17 19:43:00.749 pdfdistributor[19908:2303862] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[pdfdistributor.ViewController mLoginBT:]: unrecognized selector sent to instance 0x7fca90d17e00' *** First throw call stack:
  • Swift 3 版本:让动画 = CABasicAnimation(keyPath: "position") animation.duration = 0.07 animation.repeatCount = 4 animation.autoreverses = true animation.fromValue = NSValue(cgPoint: CGPoint(x: txtField.center.x - 10, y: txtField.center.y)) animation.toValue = NSValue(cgPoint: CGPoint(x: txtField.center.x + 10, y: txtField.center.y)) txtField.layer。添加(动画,forKey:“位置”)
  • 我的视图在 y 轴上向上移动了几个像素,然后视图动画。似乎是什么问题?
【解决方案2】:

以下函数用于任何视图。

extension UIView {
    func shake() {
        let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
        animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
        animation.duration = 0.6
        animation.values = [-20.0, 20.0, -20.0, 20.0, -10.0, 10.0, -5.0, 5.0, 0.0 ]
        layer.add(animation, forKey: "shake")
    }
}

【讨论】:

  • 如果你想让它继续抖动,请添加animation.repeatCount = 1000!
  • 在 Swift 4 中使用 name: kCAMediaTimingFunction.linear
  • @ViktorSeč 更正:适用于 Swift 4 的 CAMediaTimingFunctionName.linear
【解决方案3】:
extension CALayer {

    func shake(duration: NSTimeInterval = NSTimeInterval(0.5)) {

        let animationKey = "shake"
        removeAnimationForKey(animationKey)

        let kAnimation = CAKeyframeAnimation(keyPath: "transform.translation.x")
        kAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        kAnimation.duration = duration

        var needOffset = CGRectGetWidth(frame) * 0.15,
        values = [CGFloat]()

        let minOffset = needOffset * 0.1

        repeat {

            values.append(-needOffset)
            values.append(needOffset)
            needOffset *= 0.5
        } while needOffset > minOffset

        values.append(0)
        kAnimation.values = values
        addAnimation(kAnimation, forKey: animationKey)
    }
}

使用方法:

[UIView, UILabel, UITextField, UIButton & etc].layer.shake(NSTimeInterval(0.7))

【讨论】:

    【解决方案4】:

    这是基于 CABasicAnimation 的,它还包含一个音频效果:

    extension UIView{
        var audioPlayer = AVAudioPlayer()
        func vibrate(){
            let animation = CABasicAnimation(keyPath: "position")
            animation.duration = 0.05
            animation.repeatCount = 5
            animation.autoreverses = true
            animation.fromValue = NSValue(CGPoint: CGPointMake(self.center.x - 5.0, self.center.y))
            animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 5.0, self.center.y))
            self.layer.addAnimation(animation, forKey: "position")
            // audio part
            do {
                audioPlayer =  try AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(mySoundFileName, ofType: "mp3")!))
                audioPlayer.prepareToPlay()
                audioPlayer.play()
    
            } catch {
                print("∙ Error playing vibrate sound..")
            }
        }
    }
    

    【讨论】:

      【解决方案5】:

      编辑:如果您连续两次触发动画,使用 CABasicAnimation 会导致应用程序崩溃。所以一定要使用CAKeyframeAnimation。多亏了 cmets,Bug 已修复 :)


      如果您需要更多参数,也可以使用它(在 swift 5 中):

      public extension UIView {
      
          func shake(count : Float = 4,for duration : TimeInterval = 0.5,withTranslation translation : Float = 5) {
      
              let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
              animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
              animation.repeatCount = count
              animation.duration = duration/TimeInterval(animation.repeatCount)
              animation.autoreverses = true
              animation.values = [translation, -translation]
              layer.add(animation, forKey: "shake")
          }  
      }
      

      您可以在任何 UIView、UIButton、UILabel、UITextView 等上调用此函数。这样

      yourView.shake()
      

      或者如果你想在动画中添加一些自定义参数,可以这样:

      yourView.shake(count: 5, for: 1.5, withTranslation: 10)
      

      【讨论】:

      • 完美解决方案。简单的摇一摇我用sender.shake(count: 3, for: 0.3, withTanslation: 10)
      • 此解决方案不正确。摇动动画仅向一侧设置动画。 IE。 [-5 到 0]。正确的解决方案是 [-2.5 到 +2.5]。这种不正确的解决方案意味着抖动不会发生在视图的中心,而只是视觉上看不到。
      • 如果您尝试点击正在播放动画的 uitextfield,这实际上会崩溃。
      • 不要使用它,如果您同时执行另一个动画,它会崩溃并显示非常神秘的错误消息。你可能会崩溃提到“[NSConcreteValue doubleValue]”无法识别的选择器发送到实例致命异常:NSInvalidArgumentException 和CoreFoundation -[NSOrderedSet initWithSet:copyItems:]
      【解决方案6】:

      Swift 5.0

      extension UIView {
          func shake(){
              let animation = CABasicAnimation(keyPath: "position")
              animation.duration = 0.07
              animation.repeatCount = 3
              animation.autoreverses = true
              animation.fromValue = NSValue(cgPoint: CGPoint(x: self.center.x - 10, y: self.center.y))
              animation.toValue = NSValue(cgPoint: CGPoint(x: self.center.x + 10, y: self.center.y))
              self.layer.add(animation, forKey: "position")
          }
      }
      

      使用

      self.vwOffer.shake()
      

      【讨论】:

        【解决方案7】:

        我认为所有这些都是危险的。

        如果您的摇动动画基于用户操作,并且该用户操作是在制作动画时触发的。

        CRAAAAAAASH

        这是我在 Swift 4 中的方式:

        static func shake(view: UIView, for duration: TimeInterval = 0.5, withTranslation translation: CGFloat = 10) {
            let propertyAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 0.3) {
                view.transform = CGAffineTransform(translationX: translation, y: 0)
            }
        
            propertyAnimator.addAnimations({
                view.transform = CGAffineTransform(translationX: 0, y: 0)
            }, delayFactor: 0.2)
        
            propertyAnimator.startAnimation()
        }
        

        可能不是最干净的,但是这个方法可以反复触发,容易理解

        编辑:

        我非常支持使用 UIViewPropertyAnimator。如此多的酷炫功能可让您对基本动画进行动态修改。

        这是另一个在视图抖动时添加红色边框的示例,然后在抖动结束时将其移除。

        static func shake(view: UIView, for duration: TimeInterval = 0.5, withTranslation translation: CGFloat = 10) {
            let propertyAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 0.3) {
                view.layer.borderColor = UIColor.red.cgColor
                view.layer.borderWidth = 1
                view.transform = CGAffineTransform(translationX: translation, y: 0)
            }
        
            propertyAnimator.addAnimations({
                view.transform = CGAffineTransform(translationX: 0, y: 0)
            }, delayFactor: 0.2)
        
            propertyAnimator.addCompletion { (_) in
                view.layer.borderWidth = 0
            }
        
            propertyAnimator.startAnimation()
        }
        

        【讨论】:

        • 好吧,至少当我们在动画时尝试点击 uitextfield 时,这不会崩溃。我想在动画时添加红色边框颜色并在动画后将其删除。你打算怎么做?
        【解决方案8】:
        func shakeTextField(textField: UITextField)
        {
            let animation = CABasicAnimation(keyPath: "position")
            animation.duration = 0.07
            animation.repeatCount = 3
            animation.autoreverses = true
            animation.fromValue = NSValue(cgPoint: CGPoint(x: textField.center.x - 10, y: textField.center.y))
            animation.toValue = NSValue(cgPoint: CGPoint(x: textField.center.x + 10, y: textField.center.y))
            textField.layer.add(animation, forKey: "position")
        
            textField.attributedPlaceholder = NSAttributedString(string: textField.placeholder ?? "",
                                                                 attributes: [NSAttributedStringKey.foregroundColor: UIColor.red])
        
        }
        

        //写入基类或任何视图控制器并使用它

        【讨论】:

          【解决方案9】:

          斯威夫特 5

          Corey Pett 答案的安全(非崩溃)摇动扩展:

          extension UIView {
              func shake(for duration: TimeInterval = 0.5, withTranslation translation: CGFloat = 10) {
                  let propertyAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 0.3) {
                      self.transform = CGAffineTransform(translationX: translation, y: 0)
                  }
          
                  propertyAnimator.addAnimations({
                      self.transform = CGAffineTransform(translationX: 0, y: 0)
                  }, delayFactor: 0.2)
          
                  propertyAnimator.startAnimation()
              }
          }
          

          【讨论】:

            【解决方案10】:

            我尝试了一些可用的解决方案,但没有一个能够处理 充分摇晃 动画:从左向右移动并回到原始位置。

            所以,经过一番调查,我找到了正确的解决方案,我认为使用UIViewPropertyAnimator 是成功的。

            func shake(completion: (() -> Void)? = nil) {
                let speed = 0.75
                let time = 1.0 * speed - 0.15
                let timeFactor = CGFloat(time / 4)
                let animationDelays = [timeFactor, timeFactor * 2, timeFactor * 3]
            
                let shakeAnimator = UIViewPropertyAnimator(duration: time, dampingRatio: 0.3)
                // left, right, left, center
                shakeAnimator.addAnimations({
                    self.transform = CGAffineTransform(translationX: 20, y: 0)
                })
                shakeAnimator.addAnimations({
                    self.transform = CGAffineTransform(translationX: -20, y: 0)
                }, delayFactor: animationDelays[0])
                shakeAnimator.addAnimations({
                    self.transform = CGAffineTransform(translationX: 20, y: 0)
                }, delayFactor: animationDelays[1])
                shakeAnimator.addAnimations({
                    self.transform = CGAffineTransform(translationX: 0, y: 0)
                }, delayFactor: animationDelays[2])
                shakeAnimator.startAnimation()
            
                shakeAnimator.addCompletion { _ in
                    completion?()
                }
            
                shakeAnimator.startAnimation()
            }
            

            最终结果:

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-05-25
              • 2021-10-08
              • 1970-01-01
              • 1970-01-01
              • 2016-03-15
              相关资源
              最近更新 更多