UIView встряхнуть анимацию - PullRequest
77 голосов
/ 02 октября 2010

Я пытаюсь сотрясать UIView при нажатии кнопки.

Я адаптирую код, найденный на http://www.cimgf.com/2008/02/27/core-animation-tutorial-window-shake-effect/.

Однако, пытаясь адаптировать следующий кодпотрясти UIView, он не работает:

- (void)animate {
    const int numberOfShakes = 8;
    const float durationOfShake = 0.5f;
    const float vigourOfShake = 0.1f;

    CAKeyframeAnimation *shakeAnimation = [CAKeyframeAnimation animation];

    CGRect frame = lockView.frame;

    CGMutablePathRef shakePath = CGPathCreateMutable();
    CGPathMoveToPoint(shakePath, NULL, CGRectGetMinX(frame), CGRectGetMinY(frame));

    for (int index = 0; index < numberOfShakes; ++index) {
        CGPathAddLineToPoint(shakePath, NULL, CGRectGetMinX(frame) - frame.size.width * vigourOfShake, CGRectGetMinY(frame));

        CGPathAddLineToPoint(shakePath, NULL, CGRectGetMinX(frame) + frame.size.width * vigourOfShake, CGRectGetMinY(frame));
    }

    CGPathCloseSubpath(shakePath);

    shakeAnimation.path = shakePath;
    shakeAnimation.duration = durationOfShake;


    [lockView.layer addAnimation:shakeAnimation forKey:@"frameOrigin"];

}

Ответы [ 15 ]

192 голосов
/ 04 октября 2010

Я написал этот пост. Это излишне для UIView, плюс параметры ориентированы на приложение OSX. Сделайте это вместо этого.

CABasicAnimation *animation = 
                         [CABasicAnimation animationWithKeyPath:@"position"];
[animation setDuration:0.05];
[animation setRepeatCount:8];
[animation setAutoreverses:YES];
[animation setFromValue:[NSValue valueWithCGPoint:
               CGPointMake([lockView center].x - 20.0f, [lockView center].y)]];
[animation setToValue:[NSValue valueWithCGPoint:
               CGPointMake([lockView center].x + 20.0f, [lockView center].y)]];
[[lockView layer] addAnimation:animation forKey:@"position"];

Вам придется поиграть с параметрами продолжительности и repeatCount, а также с расстоянием x от центра в значениях from и to, но оно должно дать вам то, что вам нужно. Надеюсь, это поможет. Дайте мне знать, если у вас есть какие-либо вопросы.

---


Swift 3.0

let midX = lockView.center.x
let midY = lockView.center.y

let animation = CABasicAnimation(keyPath: "position")
animation.duration = 0.06
animation.repeatCount = 4
animation.autoreverses = true
animation.fromValue = CGPoint(x: midX - 10, y: midY)
animation.toValue = CGPoint(x: midX + 10, y: midY)
layer.add(animation, forKey: "position")
64 голосов
/ 01 октября 2015

Я предпочитаю это решение с хорошим пружинящим поведением, идеально подходящее для анимации встряхивания неправильного пароля.

view.transform = CGAffineTransformMakeTranslation(20, 0);
[UIView animateWithDuration:0.4 delay:0.0 usingSpringWithDamping:0.2 initialSpringVelocity:1.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
    view.transform = CGAffineTransformIdentity;
} completion:nil];

Свифт 3

extension UIView {
    func shake() {
        self.transform = CGAffineTransform(translationX: 20, y: 0)
        UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.2, initialSpringVelocity: 1, options: .curveEaseInOut, animations: {
            self.transform = CGAffineTransform.identity
        }, completion: nil)
    }
}
30 голосов
/ 28 июня 2013

Вот моя милая и простая на вид версия. Она имитирует дрожание, которое вы испытываете в Mac OS X при неправильном входе. Вы можете добавить это в качестве категории на UIView, если хотите.

@implementation UIView (DUExtensions)

- (void) shake {
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"];
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    animation.duration = 0.6;
    animation.values = @[ @(-20), @(20), @(-20), @(20), @(-10), @(10), @(-5), @(5), @(0) ];
    [self.layer addAnimation:animation forKey:@"shake"];  
}

@end

Значения анимации - это смещение по оси x от текущей позиции просмотра. Положительные значения смещают вид вправо, а отрицательные значения влево. Последовательно понижая их, вы получаете вибрацию, которая естественно теряет импульс. Вы можете настроить эти цифры, если хотите.

15 голосов
/ 08 мая 2015

Вот быстрая версия в качестве расширения на тот случай, если это кому-нибудь понадобится

extension UIImageView{
    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 - 2.0, self.center.y))
        animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 2.0, self.center.y))
        self.layer.addAnimation(animation, forKey: "position")
    }
}

Это оживит небольшой UIImageView (около 15x15).Если вам нужно оживить что-то большее, вы можете изменить коэффициент движения 2.0 на нечто большее.

8 голосов
/ 12 мая 2016

На основе ответа @bandejapaisa, расширение UIView для Swift 3

extension UIView {
    func shake() {
        let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.duration = 0.6
        animation.values = [-20, 20, -20, 20, -10, 10, -5, 5, 0]
        layer.addAnimation(animation, forKey: "shake")
    }
}
4 голосов
/ 29 марта 2012

Вы можете вызвать этот метод для события щелчка UIButton

-(void)shakescreen
{
    //Shake screen
    CGFloat t = 5.0;
    CGAffineTransform translateRight = CGAffineTransformTranslate(CGAffineTransformIdentity, t, t);
    CGAffineTransform translateLeft = CGAffineTransformTranslate(CGAffineTransformIdentity, -t, -t);

    self.view.transform = translateLeft;

    [UIView animateWithDuration:0.05 delay:0.0 options:UIViewAnimationOptionAutoreverse|UIViewAnimationOptionRepeat animations:^
    {
         [UIView setAnimationRepeatCount:2.0];
         self.view.transform = translateRight;
    } completion:^(BOOL finished)

      {
          if (finished) 
          {
             [UIView animateWithDuration:0.05 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
          {
              self.view.transform = CGAffineTransformIdentity;
          } 
          completion:NULL];
      }
  }];
}

Надеюсь, это поможет вам: -)

4 голосов
/ 24 января 2011

Вы можете попробовать этот кусок кода:

для вызова кода ниже, используйте: [self earthquake:myObject];

#pragma mark EarthQuake Methods

- (void)earthquake:(UIView*)itemView
{
    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); 

    CGFloat t = 2.0;

    CGAffineTransform leftQuake  = CGAffineTransformTranslate(CGAffineTransformIdentity, t, -t);
    CGAffineTransform rightQuake = CGAffineTransformTranslate(CGAffineTransformIdentity, -t, t);

    itemView.transform = leftQuake;  // starting point

    [UIView beginAnimations:@"earthquake" context:itemView];
    [UIView setAnimationRepeatAutoreverses:YES]; // important
    [UIView setAnimationRepeatCount:3];
    [UIView setAnimationDuration:0.05];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(earthquakeEnded:finished:context:)];

    itemView.transform = rightQuake; // end here & auto-reverse

    [UIView commitAnimations];
}

- (void)earthquakeEnded:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context 
{
    if ([finished boolValue]) 
    {
        UIView* item = (UIView *)context;
        item.transform = CGAffineTransformIdentity;
   }
}
3 голосов
/ 27 декабря 2014

C # Xamarin.iOS версия ответ о том, как создать анимацию встряски UIView в iOS ниже

        CAKeyFrameAnimation keyframeAnimation = CAKeyFrameAnimation.GetFromKeyPath(new NSString("transform.translation.x"));
        keyframeAnimation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut);
        keyframeAnimation.Duration = 0.6f;
        keyframeAnimation.Values = new NSObject[]{ new NSNumber(-20f), new NSNumber(20f), new NSNumber(-20f), new NSNumber(20f), new NSNumber(-10f), new NSNumber(10f), new NSNumber(-5f), new NSNumber(5f), new NSNumber(0f) };
        shakyView.Layer.AddAnimation(keyframeAnimation, "shake");
2 голосов
/ 26 октября 2016

Реализация Swift 3 на основе ответа @ Михаэля-Исаева

private enum Axis: StringLiteralType {
    case x = "x"
    case y = "y"
}

extension UIView {
    private func shake(on axis: Axis) {
        let animation = CAKeyframeAnimation(keyPath: "transform.translation.\(axis.rawValue)")
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.duration = 0.6
        animation.values = [-20, 20, -20, 20, -10, 10, -5, 5, 0]
        layer.add(animation, forKey: "shake")
    }
    func shakeOnXAxis() {
        self.shake(on: .x)
    }
    func shakeOnYAxis() {
        self.shake(on: .y)
    }
}
2 голосов
/ 12 июня 2013

Вот тот, который использует демпфирующую функцию для затухания дрожания:

- (void)shake
{
    CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    animation.duration = 0.5;
    animation.delegate = self;
    animation.fillMode = kCAFillModeForwards;
    animation.removedOnCompletion = YES;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];

    NSMutableArray* values = [[NSMutableArray alloc] init];

    int steps = 100;
    double position = 0;
    float e = 2.71;

    for (int t = 0; t < steps; t++)
    {
        position = 10 * pow(e, -0.022 * t) * sin(0.12 * t);
        NSValue* value = [NSValue valueWithCGPoint:CGPointMake([self center].x - position, [self center].y)];
        DDLogInfo(@"Value: %@", value);
        [values addObject:value];
    }

    animation.values = values;
    [[self layer] addAnimation:animation forKey:@"position"];

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...