Asked  7 Months ago    Answers:  5   Viewed   42 times

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?

 Answers

39

In 3.0, there's now an easier way - hook into the new motion events.

The main trick is that you need to have some UIView (not UIViewController) that you want as firstResponder to receive the shake event messages. Here's the code that you can use in any UIView to get shake events:

@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

You can easily transform any UIView (even system views) into a view that can get the shake event simply by subclassing the view with only these methods (and then selecting this new type instead of the base type in IB, or using it when allocating a view).

In the view controller, you want to set this view to become first responder:

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

Don't forget that if you have other views that become first responder from user actions (like a search bar or text entry field) you'll also need to restore the shaking view first responder status when the other view resigns!

This method works even if you set applicationSupportsShakeToEdit to NO.

Tuesday, June 1, 2021
 
shivam
answered 7 Months ago
19

Yup, via the onorientationchange event and the window.orientation property.

  • Documented by Apple
  • Example code on Ajaxian
Thursday, July 22, 2021
 
ALH
answered 5 Months ago
ALH
61

Been counting snores, not steps, but have some of the same issues. No actual answers, but some suggestions:

  1. Require a time interval between steps. Yes, someone can be walking slowly or jogging, but even at the fastest there is a time interval of maybe 1/5 second between steps. If "impacts" appear more rapid than that they're likely just from rebound/rattling.
  2. Rather than your fixed threshold (violence) employ a variable threshold, based on a moving average of previous events.
  3. Consider keeping separate x, y, and z thresholds, based on the assumption that the phone will not, over a short period of time, change orientation.
  4. Rather than just ignoring events stronger than a certain level, consider ignoring those outside a range, with limits specified by two thresholds (one perhaps a fraction of the other).
  5. Consider what happens when you walk -- there is a forward/backward acceleration of the body that is quite rhythmic, along with a "shock" as the foot strikes the ground. It may be best to attempt to ignore the shock (a fairly short-term signal) and instead look for the rhythmic forward/backward motion.

Another suggestion

Testing this beast "live" would be impossible. (I can imagine you trying to jog along while holding the laptop in front of you, trying to get the debugger console to focus.) What you should do is first rig your app to make some recordings (ie, write files) containing the raw measurements, then re-rig your app (#ifdefs would be handy here) to be able to "play back" those measurements so that you can step through the app with the debugger and observe its behavior.

Sunday, August 8, 2021
 
TMichel
answered 4 Months ago
48

You can use the CGRectIntersectsRect function to easily test rectangle intersection, provided the UIImageViews share the same superview (more exactly, have the same coordinate space).

Likely you will need to add code like the following:

  -(void) touchesEnded:(NSSet *) touches {
    if(CGRectIntersectsRect([imageViewA frame], [imageViewB frame])) {
      NSLog(@"Do something.");
    }
  }

to the UIView that hosts both image views, or a similar method that is called whenever the drag is completed.

Monday, August 23, 2021
 
TheCarver
answered 4 Months ago
45

Use core motion. Link your binary with CoreMotion framework. Include #import in your class. Create an instance of CMMotionManager. Set the deviceMotionUpdateInterval property to a suitable value. Then call startDeviceMotionUpdatesToQueue. You will get continuous updates inside the block, which includes acceleration, magnetic field, rotation, etc. You will get the data you require. One thing to be taken care of is that the update shall be so rapid if the interval is too small, and hence you will have to employ suitable logic to handle the same.

Wednesday, September 15, 2021
 
Shai Rado
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share