How do I detect when someone shakes an iPhone?

2018-12-31 08:06发布

I want to react when somebody shakes the iPhone. I don't particularly care how they shake it, just that it was waved vigorously about for a split second. Does anyone know how to detect this?

16条回答
谁念西风独自凉
2楼-- · 2018-12-31 08:36

Easiest solution is to derive a new root window for your application:

@implementation OMGWindow : UIWindow

- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
    if (event.type == UIEventTypeMotion && motion == UIEventSubtypeMotionShake) {
        // via notification or something   
    }
}
@end

Then in your application delegate:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[OMGWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    //…
}

If you are using a Storyboard, this may be trickier, I don’t know the code you will need in the application delegate precisely.

查看更多
不流泪的眼
3楼-- · 2018-12-31 08:39

You need to check the accelerometer via accelerometer:didAccelerate: method which is part of the UIAccelerometerDelegate protocol and check whether the values go over a threshold for the amount of movement needed for a shake.

There is decent sample code in the accelerometer:didAccelerate: method right at the bottom of AppController.m in the GLPaint example which is available on the iPhone developer site.

查看更多
妖精总统
4楼-- · 2018-12-31 08:42

To enable this app-wide, I created a category on UIWindow:

@implementation UIWindow (Utils)

- (BOOL)canBecomeFirstResponder
{
    return YES;
}

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
    if (motion == UIEventSubtypeMotionShake) {
        // Do whatever you want here...
    }
}

@end
查看更多
孤独寂梦人
5楼-- · 2018-12-31 08:44

From my Diceshaker application:

// Ensures the shake is strong enough on at least two axes before declaring it a shake.
// "Strong enough" means "greater than a client-supplied threshold" in G's.
static BOOL L0AccelerationIsShaking(UIAcceleration* last, UIAcceleration* current, double threshold) {
    double
        deltaX = fabs(last.x - current.x),
        deltaY = fabs(last.y - current.y),
        deltaZ = fabs(last.z - current.z);

    return
        (deltaX > threshold && deltaY > threshold) ||
        (deltaX > threshold && deltaZ > threshold) ||
        (deltaY > threshold && deltaZ > threshold);
}

@interface L0AppDelegate : NSObject <UIApplicationDelegate> {
    BOOL histeresisExcited;
    UIAcceleration* lastAcceleration;
}

@property(retain) UIAcceleration* lastAcceleration;

@end

@implementation L0AppDelegate

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    [UIAccelerometer sharedAccelerometer].delegate = self;
}

- (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {

    if (self.lastAcceleration) {
        if (!histeresisExcited && L0AccelerationIsShaking(self.lastAcceleration, acceleration, 0.7)) {
            histeresisExcited = YES;

            /* SHAKE DETECTED. DO HERE WHAT YOU WANT. */

        } else if (histeresisExcited && !L0AccelerationIsShaking(self.lastAcceleration, acceleration, 0.2)) {
            histeresisExcited = NO;
        }
    }

    self.lastAcceleration = acceleration;
}

// and proper @synthesize and -dealloc boilerplate code

@end

The histeresis prevents the shake event from triggering multiple times until the user stops the shake.

查看更多
登录 后发表回答