问题
I use below code for shake a view and it works properly,now i want to shake a window i change two line that i bolded in code with code2 but doesn't work
//-------- code 1
CGFloat DegreesToRadians(CGFloat degrees)
{
return degrees * M_PI / 180;
}
NSNumber* DegreesToNumber(CGFloat degrees)
{
return [NSNumber numberWithFloat:
DegreesToRadians(degrees)];
}
---------------
[self.view setWantsLayer:YES];
CAKeyframeAnimation * animation= [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
[animation setDuration:0.04];
[animation setRepeatCount:10];
srand([[NSDate date] timeIntervalSince1970]);
float rand = (float)random();
[animation setBeginTime:CACurrentMediaTime() + rand * .0000000001];
NSMutableArray *values = [NSMutableArray array];
[values addObject:DegreesToNumber(-1)];
[values addObject:DegreesToNumber(1)];
[values addObject:DegreesToNumber(-1)];
[animation setValues:values];
[self.view.layer addAnimation:animation forKey:@"rotate"];
//-------- code 2
[self.window.animator addAnimation:animation forKey:@"rotate"];
[self.window.animator setWantsLayer:YES];
回答1:
You need to add the QuartzCore Framework.
Then use the following :
#import <Quartz/Quartz.h>
//below action calls the method `shakeWindow`
- (IBAction)shake:(id)sender {
[self shakeWindow];
}
-(void)shakeWindow{
static int numberOfShakes = 3;
static float durationOfShake = 0.5f;
static float vigourOfShake = 0.05f;
CGRect frame=[self.window frame];
CAKeyframeAnimation *shakeAnimation = [CAKeyframeAnimation animation];
CGMutablePathRef shakePath = CGPathCreateMutable();
CGPathMoveToPoint(shakePath, NULL, NSMinX(frame), NSMinY(frame));
for (NSInteger 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.window setAnimations:[NSDictionary dictionaryWithObject: shakeAnimation forKey:@"frameOrigin"]];
[[self.window animator] setFrameOrigin:[self.window frame].origin];
}
回答2:
Here is a Swift version in form of NSWindow extension (based on Anoop Vaidya answer).
Possible usage :
window?.shakeWindow()
view.window?.shakeWindow()
NSApp.windows.first?.shakeWindow()
etc...
Extension (Swift 3.0) :
extension NSView {
func shake(with intensity : CGFloat = 0.05, duration : Double = 0.5 ){
let numberOfShakes = 3
let frame : CGRect = self.frame
let shakeAnimation :CAKeyframeAnimation = CAKeyframeAnimation()
let shakePath = CGMutablePath()
shakePath.move(to: CGPoint(x:NSMinX(frame),y:NSMinY(frame)))
for _ in 0...numberOfShakes-1 {
shakePath.addLine(to: CGPoint(x:NSMinX(frame) - frame.size.width * intensity,y:NSMinY(frame)))
shakePath.addLine(to: CGPoint(x:NSMinX(frame) + frame.size.width * intensity,y:NSMinY(frame)))
}
shakePath.closeSubpath()
shakeAnimation.path = shakePath
shakeAnimation.duration = duration
self.animations = ["frameOrigin":shakeAnimation]
self.animator().setFrameOrigin(self.frame.origin)
}
}
回答3:
Swift 4 Solution
let window = self.view.window
let numberOfShakes = 3
let durationOfShake = 0.4
let vigourOfShake : CGFloat = 0.03
let frame : CGRect = (window?.frame)!
let shakeAnimation :CAKeyframeAnimation = CAKeyframeAnimation()
let shakePath = CGMutablePath()
shakePath.move( to: CGPoint(x:NSMinX(frame), y:NSMinY(frame)))
for _ in 0...numberOfShakes-1 {
shakePath.addLine(to: CGPoint(x:NSMinX(frame) - frame.size.width * vigourOfShake, y:NSMinY(frame)))
shakePath.addLine(to: CGPoint(x:NSMinX(frame) + frame.size.width * vigourOfShake, y:NSMinY(frame)))
}
shakePath.closeSubpath()
shakeAnimation.path = shakePath
shakeAnimation.duration = durationOfShake
let animations = [NSAnimatablePropertyKey(rawValue: "frameOrigin") : shakeAnimation]
window?.animations = animations
window?.animator().setFrameOrigin(NSPoint(x: frame.minX, y: frame.minY))
回答4:
Swift 3 solution:
extension NSWindow {
func shakeWindow(){
let numberOfShakes = 3
let durationOfShake = 0.25
let vigourOfShake : CGFloat = 0.015
let frame : CGRect = self.frame
let shakeAnimation :CAKeyframeAnimation = CAKeyframeAnimation()
let shakePath = CGMutablePath()
shakePath.move(to: CGPoint(x: frame.minX, y: frame.minY))
for _ in 0...numberOfShakes-1 {
shakePath.addLine(to: CGPoint(x: frame.minX - frame.size.width * vigourOfShake, y: frame.minY))
shakePath.addLine(to: CGPoint(x: frame.minX + frame.size.width * vigourOfShake, y: frame.minY))
}
shakePath.closeSubpath()
shakeAnimation.path = shakePath;
shakeAnimation.duration = durationOfShake;
self.animations = ["frameOrigin":shakeAnimation]
self.animator().setFrameOrigin(self.frame.origin)
}
}
来源:https://stackoverflow.com/questions/10517386/how-to-give-nswindow-a-shake-effect-as-saying-no-as-in-login-failure-window