How to give NSWindow a shake effect as saying NO, as in Login failure window

杀马特。学长 韩版系。学妹 提交于 2019-11-29 20:58:52

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!