iOS图标微动algorithm

我正在编写一个iPad应用程序,用于呈现类似于页面呈现方式的用户文档(作为实际文档的大图标)。 我也想模仿用户点击编辑button时的跳跃行为。 当您在iPhone和iPad上轻按并按住图标时,图标在主屏幕上显示的图案也会变得相同。

我search了互联网,并find了一些algorithm,但他们只是导致视图来回摇摆,这完全不像苹果微动。 看起来有一些随机性,因为每个图标都略有不同。

有没有人有或知道一些代码,可以重新创build相同的微妙模式(或非常接近它的东西)? 谢谢!!!

@ Vic320的答案不错,但是我个人不喜欢这个翻译。 我编辑了他的代码来提供一个解决scheme,我个人觉得看起来更像跳板摇摆效果。 大多数情况下,它是通过增加一点随机性和专注于旋转来实现的,没有翻译:

#define degreesToRadians(x) (M_PI * (x) / 180.0) #define kAnimationRotateDeg 1.0 - (void)startJiggling { NSInteger randomInt = arc4random_uniform(500); float r = (randomInt/500.0)+0.5; CGAffineTransform leftWobble = CGAffineTransformMakeRotation(degreesToRadians( (kAnimationRotateDeg * -1.0) - r )); CGAffineTransform rightWobble = CGAffineTransformMakeRotation(degreesToRadians( kAnimationRotateDeg + r )); self.transform = leftWobble; // starting point [[self layer] setAnchorPoint:CGPointMake(0.5, 0.5)]; [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse animations:^{ [UIView setAnimationRepeatCount:NSNotFound]; self.transform = rightWobble; } completion:nil]; } - (void)stopJiggling { [self.layer removeAllAnimations]; self.transform = CGAffineTransformIdentity; } 

信贷的地方,虽然@ Vic320的答案提供了这个代码的基础,所以+1。

好的,所以openspringboard的代码对我来说并不是那么做,但是我确实允许我创build一些代码,我认为这样的代码更好一些,但是并不完美但是更好。 如果有人有更好的build议,我很乐意听到他们…(把这个添加到你想要跳动的视图的子类)

 #define degreesToRadians(x) (M_PI * (x) / 180.0) #define kAnimationRotateDeg 1.0 #define kAnimationTranslateX 2.0 #define kAnimationTranslateY 2.0 - (void)startJiggling:(NSInteger)count { CGAffineTransform leftWobble = CGAffineTransformMakeRotation(degreesToRadians( kAnimationRotateDeg * (count%2 ? +1 : -1 ) )); CGAffineTransform rightWobble = CGAffineTransformMakeRotation(degreesToRadians( kAnimationRotateDeg * (count%2 ? -1 : +1 ) )); CGAffineTransform moveTransform = CGAffineTransformTranslate(rightWobble, -kAnimationTranslateX, -kAnimationTranslateY); CGAffineTransform conCatTransform = CGAffineTransformConcat(rightWobble, moveTransform); self.transform = leftWobble; // starting point [UIView animateWithDuration:0.1 delay:(count * 0.08) options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse animations:^{ self.transform = conCatTransform; } completion:nil]; } - (void)stopJiggling { [self.layer removeAllAnimations]; self.transform = CGAffineTransformIdentity; // Set it straight } 

为了完整起见,下面是我如何使用一个明确的animation来激活我的CALayer子类 – 受其他答案的启发。

 -(void)stopJiggle { [self removeAnimationForKey:@"jiggle"]; } -(void)startJiggle { const float amplitude = 1.0f; // degrees float r = ( rand() / (float)RAND_MAX ) - 0.5f; float angleInDegrees = amplitude * (1.0f + r * 0.1f); float animationRotate = angleInDegrees / 180. * M_PI; // Convert to radians NSTimeInterval duration = 0.1; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; animation.duration = duration; animation.additive = YES; animation.autoreverses = YES; animation.repeatCount = FLT_MAX; animation.fromValue = @(-animationRotate); animation.toValue = @(animationRotate); animation.timeOffset = ( rand() / (float)RAND_MAX ) * duration; [self addAnimation:animation forKey:@"jiggle"]; } 

检查openspringboard项目 。

特别是,setIconAnimation:(BOOL)是在OpenSpringBoard.m中animation的。 这应该给你一些关于如何做到这一点的想法。

为了未来其他人的利益,我觉得@ Vic320提供的微动有点过于机器人,并且与Keynote相比,它有点过于强大,没有足够的随机性。 所以本着共享的精神,这里是我构build到我的UIView的子类的代码…我的视图控制器保持这些对象的数组,当用户点击编辑button时,视图控制器发送startJiggling消息给每个当用户按下“完成”button时,通过stopJiggling消息。

 - (void)startJiggling { // jiggling code based off the folks on stackoverflow.com: // http://stackoverflow.com/questions/6604356/ios-icon-jiggle-algorithm #define degreesToRadians(x) (M_PI * (x) / 180.0) #define kAnimationRotateDeg 0.1 jiggling = YES; [self wobbleLeft]; } - (void)wobbleLeft { if (jiggling) { NSInteger randomInt = arc4random()%500; float r = (randomInt/500.0)+0.5; CGAffineTransform leftWobble = CGAffineTransformMakeRotation(degreesToRadians( (kAnimationRotateDeg * -1.0) - r )); CGAffineTransform rightWobble = CGAffineTransformMakeRotation(degreesToRadians( kAnimationRotateDeg + r )); self.transform = leftWobble; // starting point [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{ self.transform = rightWobble; } completion:^(BOOL finished) { [self wobbleRight]; } ]; } } - (void)wobbleRight { if (jiggling) { NSInteger randomInt = arc4random()%500; float r = (randomInt/500.0)+0.5; CGAffineTransform leftWobble = CGAffineTransformMakeRotation(degreesToRadians( (kAnimationRotateDeg * -1.0) - r )); CGAffineTransform rightWobble = CGAffineTransformMakeRotation(degreesToRadians( kAnimationRotateDeg + r )); self.transform = rightWobble; // starting point [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{ self.transform = leftWobble; } completion:^(BOOL finished) { [self wobbleLeft]; } ]; } } - (void)stopJiggling { jiggling = NO; [self.layer removeAllAnimations]; [self setTransform:CGAffineTransformIdentity]; [self.layer setAnchorPoint:CGPointMake(0.5, 0.5)]; } 

所以我敢肯定,我会因为编写凌乱的代码而大吼一番(可能有更简单的方法来做这个,我不知道,因为我是半初学者),但是这是一个更随机的Vic320algorithm这会改变旋转和平移的数量。 它也会随机决定首先摆动哪个方向,如果你有多个东西同时摆动的话,会给出更随机的样子。 如果效率对您来说是个大问题,请不要使用。 这正是我所知道如何去做的。

任何人想知道你需要#import <QuartzCore/QuartzCore.h>并将其添加到你的链接库。

 #define degreesToRadians(x) (M_PI * (x) / 180.0) - (void)startJiggling:(NSInteger)count { double kAnimationRotateDeg = (double)(arc4random()%5 + 5) / 10; double kAnimationTranslateX = (arc4random()%4); double kAnimationTranslateY = (arc4random()%4); CGAffineTransform leftWobble = CGAffineTransformMakeRotation(degreesToRadians( kAnimationRotateDeg * (count%2 ? +1 : -1 ) )); CGAffineTransform rightWobble = CGAffineTransformMakeRotation(degreesToRadians( kAnimationRotateDeg * (count%2 ? -1 : +1 ) )); int leftOrRight = (arc4random()%2); if (leftOrRight == 0){ CGAffineTransform moveTransform = CGAffineTransformTranslate(rightWobble, -kAnimationTranslateX, -kAnimationTranslateY); CGAffineTransform conCatTransform = CGAffineTransformConcat(rightWobble, moveTransform); self.transform = leftWobble; // starting point [UIView animateWithDuration:0.1 delay:(count * 0.08) options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse animations:^{ self.transform = conCatTransform; } completion:nil]; } else if (leftOrRight == 1) { CGAffineTransform moveTransform = CGAffineTransformTranslate(leftWobble, -kAnimationTranslateX, -kAnimationTranslateY); CGAffineTransform conCatTransform = CGAffineTransformConcat(leftWobble, moveTransform); self.transform = rightWobble; // starting point [UIView animateWithDuration:0.1 delay:(count * 0.08) options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse animations:^{ self.transform = conCatTransform; } completion:nil]; } } - (void)stopJiggling { [self.layer removeAllAnimations]; self.transform = CGAffineTransformIdentity; // Set it straight } 

我扭转了工程苹果Stringboard,并修改了一点点他们的animation,下面的代码是非常好的东西。

 + (CAAnimationGroup *)jiggleAnimation { CAKeyframeAnimation *position = [CAKeyframeAnimation animation]; position.keyPath = @"position"; position.values = @[ [NSValue valueWithCGPoint:CGPointZero], [NSValue valueWithCGPoint:CGPointMake(-1, 0)], [NSValue valueWithCGPoint:CGPointMake(1, 0)], [NSValue valueWithCGPoint:CGPointMake(-1, 1)], [NSValue valueWithCGPoint:CGPointMake(1, -1)], [NSValue valueWithCGPoint:CGPointZero] ]; position.timingFunctions = @[ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] ]; position.additive = YES; CAKeyframeAnimation *rotation = [CAKeyframeAnimation animation]; rotation.keyPath = @"transform.rotation"; rotation.values = @[ @0, @0.03, @0, [NSNumber numberWithFloat:-0.02] ]; rotation.timingFunctions = @[ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] ]; CAAnimationGroup *group = [[CAAnimationGroup alloc] init]; group.animations = @[ position, rotation ]; group.duration = 0.3; group.repeatCount = HUGE_VALF; group.beginTime = arc4random() % 30 / 100.f; return group; } 

原始苹果微animation:

 CAKeyframeAnimation *position = [CAKeyframeAnimation animation]; position.beginTime = 0.8; position.duration = 0.25; position.values = @[[NSValue valueWithCGPoint:CGPointMake(-1, -1)], [NSValue valueWithCGPoint:CGPointMake(0, 0)], [NSValue valueWithCGPoint:CGPointMake(-1, 0)], [NSValue valueWithCGPoint:CGPointMake(0, -1)], [NSValue valueWithCGPoint:CGPointMake(-1, -1)]]; position.calculationMode = @"linear"; position.removedOnCompletion = NO; position.repeatCount = CGFLOAT_MAX; position.beginTime = arc4random() % 25 / 100.f; position.additive = YES; position.keyPath = @"position"; CAKeyframeAnimation *transform = [CAKeyframeAnimation animation]; transform.beginTime = 2.6; transform.duration = 0.25; transform.valueFunction = [CAValueFunction functionWithName:kCAValueFunctionRotateZ]; transform.values = @[@(-0.03525565),@(0.03525565),@(-0.03525565)]; transform.calculationMode = @"linear"; transform.removedOnCompletion = NO; transform.repeatCount = CGFLOAT_MAX; transform.additive = YES; transform.beginTime = arc4random() % 25 / 100.f; transform.keyPath = @"transform"; [self.dupa.layer addAnimation:position forKey:nil]; [self.dupa.layer addAnimation:transform forKey:nil]; 

@mientus Swift 4中的原始Apple Jiggle代码,具有可选参数来调整持续时间(即速度),位移(即位置变化)和度(即旋转量)。

 private func degreesToRadians(_ x: CGFloat) -> CGFloat { return .pi * x / 180.0 } func startWiggle( duration: Double = 0.25, displacement: CGFloat = 1.0, degreesRotation: CGFloat = 2.0 ) { let negativeDisplacement = -1.0 * displacement let position = CAKeyframeAnimation.init(keyPath: "position") position.beginTime = 0.8 position.duration = duration position.values = [ NSValue(cgPoint: CGPoint(x: negativeDisplacement, y: negativeDisplacement)), NSValue(cgPoint: CGPoint(x: 0, y: 0)), NSValue(cgPoint: CGPoint(x: negativeDisplacement, y: 0)), NSValue(cgPoint: CGPoint(x: 0, y: negativeDisplacement)), NSValue(cgPoint: CGPoint(x: negativeDisplacement, y: negativeDisplacement)) ] position.calculationMode = "linear" position.isRemovedOnCompletion = false position.repeatCount = Float.greatestFiniteMagnitude position.beginTime = CFTimeInterval(Float(arc4random()).truncatingRemainder(dividingBy: Float(25)) / Float(100)) position.isAdditive = true let transform = CAKeyframeAnimation.init(keyPath: "transform") transform.beginTime = 2.6 transform.duration = duration transform.valueFunction = CAValueFunction(name: kCAValueFunctionRotateZ) transform.values = [ degreesToRadians(-1.0 * degreesRotation), degreesToRadians(degreesRotation), degreesToRadians(-1.0 * degreesRotation) ] transform.calculationMode = "linear" transform.isRemovedOnCompletion = false transform.repeatCount = Float.greatestFiniteMagnitude transform.isAdditive = true transform.beginTime = CFTimeInterval(Float(arc4random()).truncatingRemainder(dividingBy: Float(25)) / Float(100)) self.layer.add(position, forKey: nil) self.layer.add(transform, forKey: nil) }