UIView titreme animasyonu


82

Bir düğmeye basıldığında UIView titremesi yapmaya çalışıyorum.

Http://www.cimgf.com/2008/02/27/core-animation-tutorial-window-shake-effect/ adresinde bulduğum kodu uyarlıyorum .

Ancak, aşağıdaki kodu bir UIView'ı sallayacak şekilde uyarlamaya çalıştığınızda çalışmaz:

- (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"];

}

Yanıtlar:


204

O yazıyı ben yazdım. Bir UIView için aşırıdır, ayrıca parametreler bir OSX uygulamasına yöneliktir. Bunun yerine bunu yapın.

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"];

Süre ve tekrarlama sayacı parametrelerinin yanı sıra merkezden x mesafesiyle de ve değerlerinde oynamanız gerekecek, ancak size ihtiyacınız olanı vermelidir. Umarım bu yardımcı olur. Herhangi bir sorunuz olursa bana bildirin.

---


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")

Teşekkürler, cevabınızı Xamarin IOS'ta oluşturmak için kullanıyorum Biri kullanmak isterse, işte: gist.github.com/jorwan/1ed57459c7b01b5a5b1135219e6219cf
Jorge Wander Santana Ureña

@Matt UIView'ın her sallamada rastgele yönlerde hareket etmesi için rastgele sallamak istersem ne olur?
Ehtesham Hasan

@EhteshamHasan gerçekten rastgele olamaz. Konumların / noktaların bir aralık içinde olması gerekir ve bu aralığın uç noktaları arasında (örneğin köşeden köşeye) sallanmasını istemeyebilirsiniz (bu size kalmış olsa da). Basit cevap, olası konumları (CGPoints) bir diziye koymak ve dizinizdeki nokta sayısından daha az bir indeks sağlayan bir rastgele sayı üreteci tohumlamak ve ardından cevabımda açıklanan aynı tekniği kullanarak konumu o noktaya taşımaktır.
Matt Long

78

Yanlış parola sallama animasyonu için ideal, hoş bir yaylanma davranışına sahip olan bu çözümü tercih ediyorum.

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];

Hızlı 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)
    }
}

bunu nasıl tekrar edersin şu anda yalnızca bir kez oluyor.
Crashalot

1
OP'yi doğru anladıysam, kısa bir sallama animasyonu istedi. Gerçek hayatta bir sarsıntı hareketinin sürtünmesi olduğundan ve zamanla yavaşladığından, çözümümü en uygun buluyorum. Daha uzun süre sallamak istiyorsanız, sönümleme ve initialVelocity parametrelerini deneyin. Süresiz olarak tekrarlamak istiyorsanız, diğer çözümlerden biriyle gidin.
Ortwin Gentz

bu animasyon en iyisiydi, kabul etti. sadece birkaç kez tekrarlamak istiyorum, hepsi bu.
Crashalot

Sadece uzatmak istiyorsanız, süre, sönümleme ve ilk hız değerleri ile oynamayı deneyin.
Ortwin Gentz

1
Bu çözüm, tamamlama işleyicisini kullanma olasılığı nedeniyle çok daha iyidir.
Yuri Grigoriev

34

İşte benim güzel ve basit görünümlü sürümüm Bu, yanlış bir oturum açtığınızda Mac OS X'te aldığınız titremeyi simüle eder. İsterseniz bunu UIView'de bir kategori olarak ekleyebilirsiniz.

@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

Animasyon değerleri, görünümlerin geçerli konumundan x ofsetidir. Görünümü sağa, negatif değerler sola kaydıran pozitif değerler. Art arda düşürerek, doğal olarak momentum kaybeden bir sarsıntı elde edersiniz. İsterseniz bu sayıları değiştirebilirsiniz.


1
Bunu bir UIView kategorisine yerleştirmek için harika görünüm ve sağlam fikir. UIViews titremeli, nokta!
Pedro Borges

Daha yavaş bir hızda (yani daha uzun süre) kullanıldığında, bu animasyon başka bir yanıttan tekrarlanan sayıyı kullanan birinden çok daha yumuşaktır.
Theo

Bu kodu kullandıktan sonra bazı düşünceler. Zamanlama İşlevi - varsayılan olarak doğrusaldır, bu nedenle onu ayarlamak gerekmez. Animasyon Değerleri - bir adım daha ileri gidebilir ve güzel matematiksel değerler üretmek için bir işlev tanımlayabilirsiniz ... bu da işe
Jordan Smith

17

İşte herkesin ihtiyaç duyması durumunda bir uzantı olarak hızlı sürüm

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")
    }
}

Bu, küçük bir UIImageView (yaklaşık 15x15) canlandıracaktır. Daha büyük bir şeyi canlandırmanız gerekiyorsa, 2.0 hareket faktörünü daha büyük bir şeye değiştirmek isteyebilirsiniz.


8

@Bandejapaisa cevabına göre, Swift 3 için UIView uzantısı

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

Bu kod parçasını deneyebilirsiniz:

aşağıdaki kodu aramak için şunu kullanın: [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;
   }
}

4

Bu yöntemi UIButton tıklama olayında çağırabilirsiniz

-(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];
      }
  }];
}

Umarım bu sana yardımcı olur :-)


3

İOS'ta UIView sallama animasyonu nasıl oluşturulur cevabının C # Xamarin. İOS sürümü aşağıdadır

        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

Sarsıntıyı azaltmak için bir sönümleme işlevi kullanan biri:

- (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"];

}

2

@Matt Long kodunu yeniden düzenledim ve için bir kategori oluşturdum UIView. Artık çok daha yeniden kullanılabilir ve kullanımı kolaydır.

@implementation UIView (Animation)

- (void)shakeViewWithOffest:(CGFloat)offset {
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position.x"];
    [animation setDuration:0.05];
    [animation setRepeatCount:6];
    [animation setAutoreverses:YES];
    [animation setFromValue:@([self center].x-offset)];
    [animation setToValue:@([self center].x+offset)];

    [self.layer addAnimation:animation forKey:@"position.x"];
}

- (void)shake {
    [self shakeViewWithOffest:7.0f];
}
@end

2

@ Mihael-Isaev cevabına dayalı Swift 3 uygulaması

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

Swift 4.2'de @imike cevabı

extension UIView {
func shake() {
    let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
    animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    animation.duration = 0.6
    animation.values = [-20, 20, -20, 20, -10, 10, -5, 5, 0]
    self.layer.add(animation, forKey: "shake")
}}

1
Son satır self.layer.add (animation, forKey: "shake") ile
düzeltilmelidir

1

Aşağıdaki kodu deneyebilirsiniz:

+ (void)vibrateView:(UIView*)view
{
    CABasicAnimation *shiverAnimationR;
    shiverAnimationR = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    shiverAnimationR.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(1)];
    //shiverAnimationR.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(-10)];
    shiverAnimationR.duration = 0.1;
    shiverAnimationR.repeatCount = 1000000.0; // Use A high Value
    shiverAnimationR.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

    [view.layer addAnimation: shiverAnimationR forKey:@"shiverAnimationR"];

    CABasicAnimation * shiverAnimationL;
    shiverAnimationL = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    //shiverAnimationL 2.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(10)];
    shiverAnimationL.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(-1)];
    shiverAnimationL.duration = 0.1;
    shiverAnimationL.repeatCount = 1000000.0;
    shiverAnimationL.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

    [view.layer addAnimation: shiverAnimationL forKey:@"shiverAnimationL"];

}

Bağlantıdan.


1

İşte kullanan bir sürüm,

+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion

İOS 7'de tanıtıldı.

    const CGFloat xDelta = 16.0f;

    [UIView animateKeyframesWithDuration:0.50f
                                   delay:0.0f
                                 options:UIViewKeyframeAnimationOptionCalculationModeLinear
                              animations:^{

                                  [UIView addKeyframeWithRelativeStartTime:0.0
                                                          relativeDuration:(1.0/6.0)
                                                                animations:^{
                                                                    self.passwordTextField.transform = self.usernameTextField.transform = CGAffineTransformMakeTranslation(xDelta, 0.0);
                                                                }];

                                  [UIView addKeyframeWithRelativeStartTime:(1.0/6.0)
                                                          relativeDuration:(1.0/6.0)
                                                                animations:^{
                                                                    self.passwordTextField.transform = self.usernameTextField.transform = CGAffineTransformMakeTranslation(-xDelta, 0.0);
                                                                }];

                                  [UIView addKeyframeWithRelativeStartTime:(1.0/3.0)
                                                          relativeDuration:(1.0/3.0)
                                                                animations:^{
                                                                    self.passwordTextField.transform = self.usernameTextField.transform = CGAffineTransformMakeTranslation(xDelta/2.0, 0.0);
                                                                }];

                                  [UIView addKeyframeWithRelativeStartTime:(2.0/3.0)
                                                          relativeDuration:(1.0/3.0)
                                                                animations:^{
                                                                    self.passwordTextField.transform = self.usernameTextField.transform = CGAffineTransformIdentity;
                                                                }];

                              }
                              completion:NULL];


1

Swift 4.0:

En iyi yanıta ancak animasyon üzerinde bir ayrıntılandırmaya dayanmaktadır: Bu, animasyonun başında ve sonunda atlamalara sahip değildir.

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

    let rightAnim = CABasicAnimation(keyPath: #keyPath(CALayer.position))
    rightAnim.duration      = 0.07
    rightAnim.autoreverses  = true
    rightAnim.fromValue     = CGPoint(x: midX, y: midY)
    rightAnim.toValue       = CGPoint(x: midX + 9, y: midY)

    let leftAnim = CABasicAnimation(keyPath: #keyPath(CALayer.position))
    leftAnim.duration       = 0.07
    leftAnim.autoreverses   = true
    leftAnim.fromValue      = CGPoint(x: midX, y: midY)
    leftAnim.toValue        = CGPoint(x: midX - 9, y: midY)

    let group = CAAnimationGroup()
    group.duration      = leftAnim.duration + rightAnim.duration
    group.animations    = [rightAnim, leftAnim]
    group.repeatCount   = 3

    layer.add(group, forKey: #keyPath(CALayer.position))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.