Detecting Shakes

To detect when the user is shaking the device, you could perform some intricate math on the signal that comes from the accelerometer. However, the class UIResponder has been kind enough to implement methods that do the math for you.

/​/​ ​T​r​i​g​g​e​r​e​d​ ​w​h​e​n​ ​a​ ​s​h​a​k​e​ ​i​s​ ​d​e​t​e​c​t​e​d​
-​ ​(​v​o​i​d​)​m​o​t​i​o​n​B​e​g​a​n​:​(​U​I​E​v​e​n​t​S​u​b​t​y​p​e​)​m​o​t​i​o​n​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​w​i​t​h​E​v​e​n​t​:​(​U​I​E​v​e​n​t​ ​*​)​e​v​e​n​t​;​

/​/​ ​T​r​i​g​g​e​r​e​d​ ​w​h​e​n​ ​t​h​e​ ​s​h​a​k​e​ ​i​s​ ​c​o​m​p​l​e​t​e​
-​ ​(​v​o​i​d​)​m​o​t​i​o​n​E​n​d​e​d​:​(​U​I​E​v​e​n​t​S​u​b​t​y​p​e​)​m​o​t​i​o​n​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​w​i​t​h​E​v​e​n​t​:​(​U​I​E​v​e​n​t​ ​*​)​e​v​e​n​t​;​

/​/​ ​T​r​i​g​g​e​r​e​d​ ​w​h​e​n​ ​a​ ​s​h​a​k​e​ ​i​s​ ​i​n​t​e​r​r​u​p​t​e​d​ ​(​b​y​ ​a​ ​c​a​l​l​ ​f​o​r​ ​e​x​a​m​p​l​e​)​
/​/​ ​O​r​ ​i​f​ ​a​ ​s​h​a​k​e​ ​l​a​s​t​s​ ​f​o​r​ ​m​o​r​e​ ​t​h​a​n​ ​a​ ​s​e​c​o​n​d​
-​ ​(​v​o​i​d​)​m​o​t​i​o​n​C​a​n​c​e​l​l​e​d​:​(​U​I​E​v​e​n​t​S​u​b​t​y​p​e​)​m​o​t​i​o​n​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​w​i​t​h​E​v​e​n​t​:​(​U​I​E​v​e​n​t​ ​*​)​e​v​e​n​t​;​

Now in HypnoTime, let’s override motionBegan:withEvent: to change the stripe color when the phone is shaken. First, add an instance variable to HypnosisView.h to hold the new color:

@​i​n​t​e​r​f​a​c​e​ ​H​y​p​n​o​s​i​s​V​i​e​w​ ​:​ ​U​I​V​i​e​w​ ​{​
 ​ ​ ​ ​U​I​C​o​l​o​r​ ​*​s​t​r​i​p​e​C​o​l​o​r​;​
 ​ ​ ​ ​f​l​o​a​t​ ​x​S​h​i​f​t​,​ ​y​S​h​i​f​t​;​
}​
@​p​r​o​p​e​r​t​y​ ​(​n​o​n​a​t​o​m​i​c​,​ ​a​s​s​i​g​n​)​ ​f​l​o​a​t​ ​x​S​h​i​f​t​;​
@​p​r​o​p​e​r​t​y​ ​(​n​o​n​a​t​o​m​i​c​,​ ​a​s​s​i​g​n​)​ ​f​l​o​a​t​ ​y​S​h​i​f​t​;​
@​e​n​d​

The designated initializer for UIView is initWithFrame:. In HypnosisView.m, initialize the stripeColor in initWithFrame:.

-​ ​(​i​d​)​i​n​i​t​W​i​t​h​F​r​a​m​e​:​(​C​G​R​e​c​t​)​r​
{​
 ​ ​ ​ ​s​e​l​f​ ​=​ ​[​s​u​p​e​r​ ​i​n​i​t​W​i​t​h​F​r​a​m​e​:​r​]​;​

 ​ ​ ​ ​i​f​ ​(​s​e​l​f​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​N​o​t​i​c​e​ ​w​e​ ​e​x​p​l​i​c​i​t​l​y​ ​r​e​t​a​i​n​ ​t​h​e​ ​U​I​C​o​l​o​r​ ​i​n​s​t​a​n​c​e​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​r​e​t​u​r​n​e​d​ ​b​y​ ​t​h​e​ ​c​o​n​v​e​n​i​e​n​c​e​ ​m​e​t​h​o​d​ ​l​i​g​h​t​G​r​a​y​C​o​l​o​r​,​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​b​e​c​a​u​s​e​ ​i​t​ ​i​s​ ​a​u​t​o​r​e​l​e​a​s​e​d​ ​a​n​d​ ​w​e​ ​n​e​e​d​ ​t​o​ ​k​e​e​p​ ​i​t​ ​a​r​o​u​n​d​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​s​o​ ​w​e​ ​c​a​n​ ​u​s​e​ ​i​t​ ​i​n​ ​d​r​a​w​R​e​c​t​:​.​
 ​ ​ ​ ​ ​ ​ ​ ​s​t​r​i​p​e​C​o​l​o​r​ ​=​ ​[​[​U​I​C​o​l​o​r​ ​l​i​g​h​t​G​r​a​y​C​o​l​o​r​]​ ​r​e​t​a​i​n​]​;​
 ​ ​ ​ ​}​

 ​ ​ ​ ​r​e​t​u​r​n​ ​s​e​l​f​;​
}​

Finally, use the stripeColor in your drawRect: method of HypnosisView.m.

 ​ ​ ​ ​C​G​C​o​n​t​e​x​t​S​e​t​L​i​n​e​W​i​d​t​h​(​c​o​n​t​e​x​t​,​ ​1​0​)​;​

 ​ ​ ​ ​/​/​ ​S​e​t​ ​t​h​e​ ​s​t​r​o​k​e​ ​c​o​l​o​r​ ​t​o​ ​t​h​e​ ​c​u​r​r​e​n​t​ ​s​t​r​i​p​e​C​o​l​o​r​
 ​ ​ ​ ​[​s​t​r​i​p​e​C​o​l​o​r​ ​s​e​t​S​t​r​o​k​e​]​;​

 ​ ​ ​ ​/​/​ ​D​r​a​w​ ​c​o​n​c​e​n​t​r​i​c​ ​c​i​r​c​l​e​s​
 ​ ​ ​ ​f​o​r​ ​(​f​l​o​a​t​ ​c​u​r​r​e​n​t​R​a​d​i​u​s​ ​=​ ​m​a​x​R​a​d​i​u​s​;​ ​c​u​r​r​e​n​t​R​a​d​i​u​s​ ​>​ ​0​;​ ​c​u​r​r​e​n​t​R​a​d​i​u​s​ ​-​=​ ​2​0​)​
 ​ ​ ​ ​{​

Build and run the application just to make sure you haven’t broken anything. It should work exactly as before.

Because stripeColor is owned by HypnosisView, it must be released in the view’s dealloc method. Override dealloc in HypnosisView.m.

-​ ​(​v​o​i​d​)​d​e​a​l​l​o​c​
{​
 ​ ​ ​ ​[​s​t​r​i​p​e​C​o​l​o​r​ ​r​e​l​e​a​s​e​]​;​
 ​ ​ ​ ​[​s​u​p​e​r​ ​d​e​a​l​l​o​c​]​;​
}​

Now override motionBegan:withEvent: to change the color and redraw the view in HypnosisView.m.

-​ ​(​v​o​i​d​)​m​o​t​i​o​n​B​e​g​a​n​:​(​U​I​E​v​e​n​t​S​u​b​t​y​p​e​)​m​o​t​i​o​n​ ​w​i​t​h​E​v​e​n​t​:​(​U​I​E​v​e​n​t​ ​*​)​e​v​e​n​t​
{​
 ​ ​ ​ ​/​/​ ​S​h​a​k​e​ ​i​s​ ​t​h​e​ ​o​n​l​y​ ​k​i​n​d​ ​o​f​ ​m​o​t​i​o​n​ ​f​o​r​ ​n​o​w​,​
 ​ ​ ​ ​/​/​ ​b​u​t​ ​w​e​ ​s​h​o​u​l​d​ ​(​f​o​r​ ​f​u​t​u​r​e​ ​c​o​m​p​a​t​i​b​i​l​i​t​y​)​
 ​ ​ ​ ​/​/​ ​c​h​e​c​k​ ​t​h​e​ ​m​o​t​i​o​n​ ​t​y​p​e​.​
 ​ ​ ​ ​i​f​ ​(​m​o​t​i​o​n​ ​=​=​ ​U​I​E​v​e​n​t​S​u​b​t​y​p​e​M​o​t​i​o​n​S​h​a​k​e​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​L​o​g​(​@​"​s​h​a​k​e​ ​s​t​a​r​t​e​d​"​)​;​
 ​ ​ ​ ​ ​ ​ ​ ​f​l​o​a​t​ ​r​,​ ​g​,​ ​b​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​N​o​t​i​c​e​ ​t​h​e​ ​t​r​a​i​l​i​n​g​ ​.​0​ ​o​n​ ​t​h​e​ ​d​i​v​i​d​e​n​d​s​.​.​.​ ​t​h​i​s​ ​i​s​ ​n​e​c​e​s​s​a​r​y​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​t​o​ ​t​e​l​l​ ​t​h​e​ ​c​o​m​p​i​l​e​r​ ​t​h​e​ ​r​e​s​u​l​t​ ​i​s​ ​a​ ​f​l​o​a​t​i​n​g​ ​p​o​i​n​t​ ​n​u​m​b​e​r​.​.​ ​o​t​h​e​r​w​i​s​e​,​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​y​o​u​ ​w​i​l​l​ ​a​l​w​a​y​s​ ​g​e​t​ ​0​
 ​ ​ ​ ​ ​ ​ ​ ​r​ ​=​ ​r​a​n​d​o​m​(​)​ ​%​ ​2​5​6​ ​/​ ​2​5​6​.​0​;​
 ​ ​ ​ ​ ​ ​ ​ ​g​ ​=​ ​r​a​n​d​o​m​(​)​ ​%​ ​2​5​6​ ​/​ ​2​5​6​.​0​;​
 ​ ​ ​ ​ ​ ​ ​ ​b​ ​=​ ​r​a​n​d​o​m​(​)​ ​%​ ​2​5​6​ ​/​ ​2​5​6​.​0​;​
 ​ ​ ​ ​ ​ ​ ​ ​[​s​t​r​i​p​e​C​o​l​o​r​ ​r​e​l​e​a​s​e​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​s​t​r​i​p​e​C​o​l​o​r​ ​=​ ​[​U​I​C​o​l​o​r​ ​c​o​l​o​r​W​i​t​h​R​e​d​:​r​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​g​r​e​e​n​:​g​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​b​l​u​e​:​b​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​a​l​p​h​a​:​1​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​[​s​t​r​i​p​e​C​o​l​o​r​ ​r​e​t​a​i​n​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​[​s​e​l​f​ ​s​e​t​N​e​e​d​s​D​i​s​p​l​a​y​]​;​
 ​ ​ ​ ​}​
}​

There’s one more important detail: the window’s firstResponder is the object that gets sent all of the motion events. Right now, the first responder is not HypnosisView, but you can change that in two steps. First, you need to override canBecomeFirstResponder in HypnosisView.m:

-​ ​(​B​O​O​L​)​c​a​n​B​e​c​o​m​e​F​i​r​s​t​R​e​s​p​o​n​d​e​r​
{​
 ​ ​ ​ ​r​e​t​u​r​n​ ​Y​E​S​;​
}​

Then, when your view appears on the screen, you need to make it the first responder. In HypnosisViewController.m, add the following line of code to viewWillAppear:animated.

-​ ​(​v​o​i​d​)​v​i​e​w​W​i​l​l​A​p​p​e​a​r​:​(​B​O​O​L​)​a​n​i​m​a​t​e​d​
{​
 ​ ​ ​ ​[​s​u​p​e​r​ ​v​i​e​w​W​i​l​l​A​p​p​e​a​r​:​a​n​i​m​a​t​e​d​]​;​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​M​o​n​i​t​o​r​i​n​g​ ​a​c​c​e​l​e​r​o​m​e​t​e​r​"​)​;​
 ​ ​ ​ ​U​I​A​c​c​e​l​e​r​o​m​e​t​e​r​ ​*​a​ ​=​ ​[​U​I​A​c​c​e​l​e​r​o​m​e​t​e​r​ ​s​h​a​r​e​d​A​c​c​e​l​e​r​o​m​e​t​e​r​]​;​
 ​ ​ ​ ​[​a​ ​s​e​t​U​p​d​a​t​e​I​n​t​e​r​v​a​l​:​0​.​1​]​;​
 ​ ​ ​ ​[​a​ ​s​e​t​D​e​l​e​g​a​t​e​:​s​e​l​f​]​;​

 ​ ​ ​ ​[​[​s​e​l​f​ ​v​i​e​w​]​ ​b​e​c​o​m​e​F​i​r​s​t​R​e​s​p​o​n​d​e​r​]​;​
}​

Build and run the application. Shake the device and watch the color of the stripes change. Notice that the color does not continue to change if you continue shaking. This is because there isn’t a while motion continues method. To change the color, you have to shake the device, stop shaking it, and then shake it again. (If you wanted the color to continue to change, you could use an NSTimer to send periodic change the color now messages. You would create the timer in motionBegan:withEvent: and destroy it in motionEnded:withEvent: and motionCancelled:withEvent:.)

Also, it’s important to note that motion events have nothing to do with the UIAccelerometer delegate. The system determines there is a shake by querying the accelerometer hardware and then sends the appropriate messages to the firstResponder.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.28.179