如何检测有人摇晃 iPhone?
我想在有人摇晃 iPhone 时做出反应。 我并不特别关心他们如何摇动它,只是在瞬间用力挥动它。 有谁知道如何检测这个?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
为了在应用程序范围内启用此功能,我在 UIWindow 上创建了一个类别:
To enable this app-wide, I created a category on UIWindow:
在 swift 5 中,您可以这样捕捉运动并检查
In swift 5, this is how you can capture motion and check
最简单的解决方案是为您的应用程序派生一个新的根窗口:
然后在您的应用程序委托中:
如果您使用的是故事板,这可能会更棘手,我不知道您在应用程序委托中确切需要的代码。
Easiest solution is to derive a new root window for your application:
Then in your application delegate:
If you are using a Storyboard, this may be trickier, I don’t know the code you will need in the application delegate precisely.
只需使用这三种方法即可完成
详细信息,您可以通过 那里
Just use these three methods to do it
for details you may check a complete example code over there
基于第一个答案的 swiftease 版本!
A swiftease version based on the very first answer!
查看 GLPaint 示例。
http://developer.apple.com/library/ios /#samplecode/GLPaint/Introduction/Intro.html
Check out the GLPaint example.
http://developer.apple.com/library/ios/#samplecode/GLPaint/Introduction/Intro.html
在ViewController.m文件中添加以下方法,其工作正常
Add Following methods in ViewController.m file, its working properly
这是您需要的基本委托代码:
还要在接口中的适当代码中设置 。 即:
@interface MyViewController : UIViewController
This is the basic delegate code you need:
Also set the in the appropriate code in the Interface. i.e:
@interface MyViewController : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource, UIAccelerometerDelegate>
您需要通过 accelerometer:didAccelerate: 方法(UIAccelerometerDelegate 协议的一部分)检查加速度计,并检查这些值是否超过摇动所需移动量的阈值。
GLPaint 示例中 AppController.m 底部的 Accelerometer:didAccelerate: 方法中有不错的示例代码,该示例可在 iPhone 开发人员网站上找到。
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.
在使用 Swift 的 iOS 8.3(可能更早)中,只需重写视图控制器中的
motionBegan
或motionEnded
方法即可:In iOS 8.3 (perhaps earlier) with Swift, it's as simple as overriding the
motionBegan
ormotionEnded
methods in your view controller:首先,我知道这是一篇旧帖子,但它仍然相关,而且我发现得票最高的两个答案没有尽早检测到震动。 操作方法如下:
在你的 ViewController 中:
First off, I know this is an old post, but it is still relevant, and I found that the two highest voted answers did not detect the shake as early as possible. This is how to do it:
In your ViewController:
很抱歉将此作为答案而不是评论发布,但正如您所看到的,我是 Stack Overflow 的新手,所以我还没有足够的信誉来发表评论!
不管怎样,我同意@cire,一旦视图成为视图层次结构的一部分,就确保设置第一响应者状态。 因此,在视图控制器
viewDidLoad
方法中设置第一响应者状态将不起作用。 如果您不确定它是否正常工作,[viewBecomeFirstResponder]
会返回一个可以测试的布尔值。另一点:如果您不想不必要地创建 UIView 子类,您可以使用视图控制器来捕获摇动事件。 我知道这并没有那么麻烦,但仍然有选择。 只需将 Kendall 放入 UIView 子类的代码片段移至控制器中,并将
becomeFirstResponder
和resignFirstResponder
消息发送到self
而不是 UIView 子类。Sorry to post this as an answer rather than a comment but as you can see I'm new to Stack Overflow and so I'm not yet reputable enough to post comments!
Anyway I second @cire about making sure to set the first responder status once the view is part of the view hierarchy. So setting first responder status in your view controllers
viewDidLoad
method won't work for example. And if you're unsure as to whether it is working[view becomeFirstResponder]
returns you a boolean that you can test.Another point: you can use a view controller to capture the shake event if you don't want to create a UIView subclass unnecessarily. I know it's not that much hassle but still the option is there. Just move the code snippets that Kendall put into the UIView subclass into your controller and send the
becomeFirstResponder
andresignFirstResponder
messages toself
instead of the UIView subclass.我发现这篇文章正在寻找“震撼”的实现。 millenomi的答案对我来说效果很好,尽管我正在寻找需要更多“震动动作”才能触发的东西。 我已将布尔值替换为 int shakeCount。 我还在 Objective-C 中重新实现了 L0AccelerationIsShaking() 方法。 您可以通过调整添加到 shakeCount 的数量来调整所需的摇动量。 我不确定我是否已经找到最佳值,但到目前为止它似乎运行良好。 希望这对某人有帮助:
PS:
我已将更新间隔设置为 1/15 秒。
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:
PS:
I've set the update interval to 1/15th of a second.
从我的 Diceshaker 应用程序:
滞后现象可防止多次触发摇动事件,直到用户停止摇动。
From my Diceshaker application:
The histeresis prevents the shake event from triggering multiple times until the user stops the shake.
我终于使用此 撤消/重做管理器教程。
这正是您需要做的:
I finally made it work using code examples from this Undo/Redo Manager Tutorial.
This is exactly what you need to do:
首先,肯德尔 7 月 10 日的回答是正确的。
现在...我想做类似的事情(在 iPhone OS 3.0+ 中),只是在我的情况下,我希望在应用程序范围内使用它,这样当发生震动时我可以向应用程序的各个部分发出警报。 这就是我最终所做的。
首先,我对 UIWindow 进行了子类化。 这很容易。 使用诸如
MotionWindow : UIWindow
之类的界面创建一个新的类文件(当然,您可以随意选择)。 添加如下方法:将
@"DeviceShaken"
更改为您选择的通知名称。 保存文件。现在,如果您使用 MainWindow.xib(库存 Xcode 模板内容),请进入那里并将 Window 对象的类从 UIWindow 更改为 MotionWindow 或您所称的任何名称。 拯救xib。 如果您以编程方式设置 UIWindow,请改用新的 Window 类。
现在您的应用程序正在使用专门的 UIWindow 类。 无论您想在哪里得知震动的消息,请注册接收通知! 像这样:
要删除自己作为观察者:
我将我的放在涉及视图控制器的 viewWillAppear: 和 viewWillDisappear: 中。 确保您对摇动事件的响应知道它是否“已在进行中”。 否则,如果设备连续晃动两次,就会出现轻微的交通拥堵。 这样您就可以忽略其他通知,直到您真正完成对原始通知的响应。
另外:您可以选择提示 motionBegan 与 motionEnded。 由你决定。 就我而言,效果总是需要在设备处于静止状态(相对于设备开始晃动时)之后发生,因此我使用motionEnded。 尝试两者,看看哪一个更有意义……或者检测/通知两者!
这里还有一个(好奇?)观察:请注意,此代码中没有第一响应者管理的迹象。 到目前为止,我只尝试过使用表视图控制器,一切似乎都配合得很好! 但我不能保证其他情况。
肯德尔等。 al - 谁能解释一下为什么 UIWindow 子类会出现这种情况? 是因为窗户位于食物链的顶端吗?
First, Kendall's July 10th answer is spot-on.
Now ... I wanted to do something similar (in iPhone OS 3.0+), only in my case I wanted it app-wide so I could alert various parts of the app when a shake occurred. Here's what I ended up doing.
First, I subclassed UIWindow. This is easy peasy. Create a new class file with an interface such as
MotionWindow : UIWindow
(feel free to pick your own, natch). Add a method like so:Change
@"DeviceShaken"
to the notification name of your choice. Save the file.Now, if you use a MainWindow.xib (stock Xcode template stuff), go in there and change the class of your Window object from UIWindow to MotionWindow or whatever you called it. Save the xib. If you set up UIWindow programmatically, use your new Window class there instead.
Now your app is using the specialized UIWindow class. Wherever you want to be told about a shake, sign up for them notifications! Like this:
To remove yourself as an observer:
I put mine in viewWillAppear: and viewWillDisappear: where View Controllers are concerned. Be sure your response to the shake event knows if it is "already in progress" or not. Otherwise, if the device is shaken twice in succession, you'll have a li'l traffic jam. This way you can ignore other notifications until you're truly done responding to the original notification.
Also: You may choose to cue off of motionBegan vs. motionEnded. It's up to you. In my case, the effect always needs to take place after the device is at rest (vs. when it starts shaking), so I use motionEnded. Try both and see which one makes more sense ... or detect/notify for both!
One more (curious?) observation here: Notice there's no sign of first responder management in this code. I've only tried this with Table View Controllers so far and everything seems to work quite nicely together! I can't vouch for other scenarios though.
Kendall, et. al - can anyone speak to why this might be so for UIWindow subclasses? Is it because the window is at the top of the food chain?
在 3.0 中,现在有一种更简单的方法 - 挂钩新的运动事件。
主要技巧是您需要有一些 UIView (不是 UIViewController)作为firstResponder 来接收摇动事件消息。 以下是您可以在任何 UIView 中使用来获取摇动事件的代码:
您可以轻松地将任何 UIView(甚至是系统视图)转换为可以获取摇动事件的视图,只需使用这些方法对视图进行子类化(然后选择这个新的类型而不是 IB 中的基本类型,或者在分配视图时使用它)。
在视图控制器中,您希望将此视图设置为第一响应者:
不要忘记,如果您有其他视图通过用户操作(例如搜索栏或文本输入字段)成为第一响应者,您还需要恢复当其他视图退出时,晃动视图第一响应者状态!
即使您将 applicationSupportsShakeToEdit 设置为 NO,此方法也有效。
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:
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:
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.