当有人摇晃iPhone时,我想做出反应。我并不特别在意他们是如何摇晃它的,只在意它在一瞬间被使劲地挥舞着。有人知道怎么检测吗?


当前回答

首先,我知道这是一个老帖子,但它仍然是相关的,我发现投票最高的两个答案并没有尽早检测到震动。下面是如何做到这一点:

将CoreMotion链接到目标构建阶段的项目: 在你的ViewController中: - (BOOL)canBecomeFirstResponder { 返回YES; } - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event { if(运动== UIEventSubtypeMotionShake) { //检测到震动。 } }

其他回答

I came across this post looking for a "shaking" implementation. millenomi's answer worked well for me, although i was looking for something that required a bit more "shaking action" to trigger. I've replaced to Boolean value with an int shakeCount. I also reimplemented the L0AccelerationIsShaking() method in Objective-C. You can tweak the ammount of shaking required by tweaking the ammount added to shakeCount. I'm not sure i've found the optimal values yet, but it seems to be working well so far. Hope this helps someone:

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    if (self.lastAcceleration) {
        if ([self AccelerationIsShakingLast:self.lastAcceleration current:acceleration threshold:0.7] && shakeCount >= 9) {
            //Shaking here, DO stuff.
            shakeCount = 0;
        } else if ([self AccelerationIsShakingLast:self.lastAcceleration current:acceleration threshold:0.7]) {
            shakeCount = shakeCount + 5;
        }else if (![self AccelerationIsShakingLast:self.lastAcceleration current:acceleration threshold:0.2]) {
            if (shakeCount > 0) {
                shakeCount--;
            }
        }
    }
    self.lastAcceleration = acceleration;
}

- (BOOL) AccelerationIsShakingLast:(UIAcceleration *)last current:(UIAcceleration *)current threshold:(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);
}

PS: 我将更新间隔设置为1/15秒。

[[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / 15)];

在3.0,现在有一个更简单的方法-挂钩到新的运动事件。

主要的技巧是你需要有一些UIView(不是UIViewController)你想要作为firstResponder来接收震动事件消息。这是你可以在任何UIView中使用的代码来获取震动事件:

@implementation ShakingView

- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
    if ( event.subtype == UIEventSubtypeMotionShake )
    {
        // Put in code here to handle shake
    }

    if ( [super respondsToSelector:@selector(motionEnded:withEvent:)] )
        [super motionEnded:motion withEvent:event];
}

- (BOOL)canBecomeFirstResponder
{ return YES; }

@end

你可以很容易地将任何UIView(甚至是系统视图)转换为一个视图,只需用这些方法子类化视图(然后选择这个新类型而不是IB中的基类型,或者在分配视图时使用它)就可以获得抖动事件。

在视图控制器中,你想要将这个视图设置为第一响应器:

- (void) viewWillAppear:(BOOL)animated
{
    [shakeView becomeFirstResponder];
    [super viewWillAppear:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
    [shakeView resignFirstResponder];
    [super viewWillDisappear:animated];
}

不要忘记,如果你有其他视图成为用户操作的第一响应器(如搜索栏或文本输入字段),当其他视图退出时,你还需要恢复震动视图的第一响应器状态!

即使您将applicationSupportsShakeToEdit设置为NO,此方法也有效。

在我的Diceshaker应用中:

// 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

组织性可以防止震动事件多次触发,直到用户停止震动。

在ViewController中添加以下方法。M文件,它的工作正常

    -(BOOL) canBecomeFirstResponder
    {
         /* Here, We want our view (not viewcontroller) as first responder 
         to receive shake event message  */

         return YES;
    }

    -(void) motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
    {
            if(event.subtype==UIEventSubtypeMotionShake)
            {
                    // Code at shake event

                    UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"Motion" message:@"Phone Vibrate"delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil];
                    [alert show];
                    [alert release];

                    [self.view setBackgroundColor:[UIColor redColor]];
             }
    }
    - (void)viewDidAppear:(BOOL)animated
    {
             [super viewDidAppear:animated];
             [self becomeFirstResponder];  // View as first responder 
     }

在swift 5中,这就是如何捕捉运动并进行检查

override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
   if motion == .motionShake 
   {
      print("shaking")
   }
}