01 窗口抖動
創(chuàng)建一個NSWindow的分類,我取名為NSWindow+Animation
自定義抖屏方法,實現(xiàn)beginShakeAnimation方法,如下截圖所示:

為了方便大家取用,摘抄代碼復(fù)制如下:
static NSInteger const numberOfShakes = 20;
static float const durationOfShake = 0.5f;
static float const vigourOfShake = 0.01f;
- (void)beginShakeAnimation
{
CGRect frame = self.frame;
CAKeyframeAnimation *shakeAnimation = [CAKeyframeAnimation animation];
CGMutablePathRef shakePath = CGPathCreateMutable();
CGPathMoveToPoint(shakePath, NULL, NSMinX(frame), NSMinY(frame));
int index;
for (index = 0; index < numberOfShakes; ++index)
{
CGPathAddLineToPoint(shakePath, NULL, NSMinX(frame) - frame.size.width * vigourOfShake, NSMinY(frame));
CGPathAddLineToPoint(shakePath, NULL, NSMinX(frame) + frame.size.width * vigourOfShake, NSMinY(frame));
}
CGPathCloseSubpath(shakePath);
shakeAnimation.path = shakePath;
shakeAnimation.duration = durationOfShake;
[self setAnimations:@{@"frameOrigin" : shakeAnimation}];
[[self animator] setFrameOrigin:self.frame.origin];
}
02 視圖抖動
如果你的需求不是整個窗口抖動,而是某個視圖抖動,就需要用layer的關(guān)鍵幀動畫來實現(xiàn)。
創(chuàng)建一個NSView的分類,我取名為NSView+Animation
自定義抖屏方法,實現(xiàn)beginShakeAnimation方法,如下截圖所示:

為了方便大家取用,摘抄代碼復(fù)制如下:
//角度轉(zhuǎn)化為弧度
#define kToRadian(x) (M_PI/180 * (x))
- (void)beginShakeAnimation
{
//視圖抖動
CAKeyframeAnimation *keyframeAni = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
keyframeAni.duration = 0.2;
//關(guān)鍵部分角度
keyframeAni.values = @[@(kToRadian(5)),@(kToRadian(0)),@(kToRadian(-5)),@(kToRadian(0)),@(kToRadian(5))];
keyframeAni.repeatCount = 5;
NSRect viewRect = self.frame;
CGFloat posX = NSMinX(viewRect) + NSWidth(viewRect) * 0.5;
CGFloat posY = NSMinY(viewRect) + NSHeight(viewRect) * 0.5;
self.layer.position = CGPointMake(posX, posY);
self.layer.anchorPoint = CGPointMake(0.5, 0.5);
[self.layer addAnimation:keyframeAni forKey:@"key"];
}
需要注意的是:mac應(yīng)用的關(guān)鍵幀動畫圓點是視圖原點,ios的圓點視圖是中心,所以mac需要修改一下position和anchorPoint。
總結(jié):如果是窗口抖動,使用NSWindow的setAnimations方法;如果是視圖抖動,使用NSView.layer的關(guān)鍵幀動畫。