iOS:如何检测摇晃手势?

25

我在appDelegate.m文件中添加了以下代码

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
}

- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
    if (motion == UIEventSubtypeMotionShake )
    {
        // User was shaking the device. Post a notification named "shake".
        [[NSNotificationCenter defaultCenter] postNotificationName:@"shake" object:self];
    }
}

- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
{   
}

- (void)shakeSuccess
{
    // do something...
}

然后我添加了:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    // INIT THE BACKGROUND PATH STRING

    [self refreshFields];
    [self.window addSubview:navController.view];
    [self.window makeKeyAndVisible];
    ***[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shakeSuccess) name:@"shake" object:nil];***

    return YES;
}

当我在iPhone上启动我的应用程序时,名为"shakeSuccess"的方法没有被调用。 我该怎么做才能在我的应用程序中实现这个功能? 有什么想法吗?

5个回答

59
这可能会对你有所帮助...
https://dev59.com/AnVC5IYBdhLWcg3w51lv#2405692

他说你应该将UIApplicationapplicationSupportsShakeToEdit设置为YES。并在你的VC中覆盖3个方法:

-(BOOL)canBecomeFirstResponder {
    return YES;
}

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self becomeFirstResponder];
}

- (void)viewWillDisappear:(BOOL)animated {
    [self resignFirstResponder];
    [super viewWillDisappear:animated];
}

你的代码其余部分是正确的。(即 -motionEnded:withEvent:)


21
哈哈,他从来没有做过。 - Andrew Plummer
为什么在 [super viewWillDisappear:animated]; 之前调用 [self resignFirstResponder];?这似乎很奇怪。 - JaredH

26

你可以像这样做...

首先...

在应用程序的代理中设置applicationSupportsShakeToEdit属性:

- (void)applicationDidFinishLaunching:(UIApplication *)application {

    application.applicationSupportsShakeToEdit = YES;

    [window addSubview:viewController.view];
    [window makeKeyAndVisible];
}

其次...

在您的视图控制器中添加/覆盖canBecomeFirstResponder、viewDidAppear:和viewWillDisappear:方法:

-(BOOL)canBecomeFirstResponder {
    return YES;
}

-(void)viewDidAppear:(BOOL)animated {
   [super viewDidAppear:animated];
   [self becomeFirstResponder];
}

- (void)viewWillDisappear:(BOOL)animated {
    [self resignFirstResponder];
    [super viewWillDisappear:animated];
 }

第三...

将motionEnded方法添加到您的视图控制器中:

- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
   if (motion == UIEventSubtypeMotionShake)
   {
    // your code
   }
 }

如果第一个答案不起作用,那么这应该可以,并且这只是快速输入而没有经过测试:)


14

如果你想在整个应用中检测晃动动作,最好的方法是使用自定义类来覆盖应用程序的类。

然后在你的自定义应用程序类中实现这一点。

@implementation PSApplication

- (void)sendEvent:(UIEvent *)event
{
    if ( event.type == UIEventTypeMotion && event.subtype == UIEventSubtypeMotionShake ) {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"shakeNotification" object:nil];
    }

    [super sendEvent:event];
}

@end

4
这是寻找全局应用内摇晃检测代码的最佳答案,不受单个视图控制器限制。 - Rafał Sroka
为了在 main.m 中覆盖 UIApplication,请添加以下代码:return UIApplicationMain(argc, argv, @"PSApplication", NSStringFromClass([AppDelegate class])); - Ciprian Rarau
为什么不能直接子类化 - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event ? - JakubKnejzlik
你也可以这样做,我猜... :-) 有多种方法可以完成同一件事情。但是如果你的UIApplication不是第一响应者,它还能正常工作吗? - Cherpak Evgeny
2
每次摇晃将会触发两个发送事件。已在模拟器中测试。 - Aliaksandr Bialiauski

3

我扩展了UIApplication类,并将类引用添加到了主文件:MyApplication.h

@interface MyApplication : UIApplication

@end

MyApplication.m

@implementation MyApplication

- (void) sendEvent:(UIEvent *)event
{
    if( event && (event.subtype==UIEventSubtypeMotionShake))
    {
        AppDelegate *objAppDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

        [objAppDelegate doWhatEver];
        [super sendEvent:event];
    }
    else
    {
        [super sendEvent:event];
    }
}

@end

在main.m文件中的最后一步是:
int main(int argc, char *argv[])
{
return UIApplicationMain(argc, argv, NSStringFromClass([MyApplication class]), NSStringFromClass([AppDelegate class]));
}

这适用于所有情况。


不错的解决方案!干杯 - Jim Tierney

0

快速检测全局摇动动作

创建自定义的UIWindow类

import UIKit

class CustomWindow : UIWindow {
    override var canBecomeFirstResponder: Bool {
        return true
    }
    
    override func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
        guard motion == .motionShake else {
            return
        }
        
        //logic is here
    }
}

设置CustomWindow
class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: CustomWindow!

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }

        //inti view controller as you wish
        //or if your storyboard has `Is Initial View Controller`
        let storyboard = UIStoryboard(name: String(describing: SomeViewController.self), bundle: nil)
        let vc = storyboard.instantiateInitialViewController()

        window = CustomWindow(windowScene: windowScene)
        window.rootViewController = vc
        window.makeKeyAndVisible()
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接