I am running into a bit of a problem when I attempt to use (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event in order to capture a shake event. The problem is that the function isn't even running, even when I override canBecomeFirstResponder and set it to return YES. I have seen some other people's posts with this problem, but I have not found an answer.
Thanks for any help!
First Example .h (class inherited from UIView - Is "called" from the app delegate class) {
@class TestApplicationView;
@interface TestApplicationView : UIView {
IBOutlet UIView *view;
}
}
First Example .m {
- (id)initWithCoder:(NSCoder *)coder
{
[self setUpView];
return self;
}
- (id)initWithFrame:(CGRect)frame
{
[self setUpView];
return self;
}
- (void)setUpView
{
[self becomeFirstResponder];
NSLog(@"First Responder - %d", [self isFirstResponder]);
}
}
Second Example .h (class inherited from UIApplicationDelegate and UIScrollViewDelegate) {
#import <UIKit/UIKit.h>
@class TestApplicationViewController;
@interface TestApplicationAppDelegate : NSObject <UIApplicationDelegate, UIScrollViewDelegate> {
IBOutlet UIWindow *window;
IBOutlet UIScrollView *scrollView;
}
}
Second Example .m {
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
[self becomeFirstResponder];
}
}
-- The second example returns the following warning: 'TestApplicationAppDelegate' may not respond to '-becomeFirstResponder'
I assume you want to implement this in a subclass of UIViewController
. Make the UIViewController
capable of becoming first responder:
- (BOOL)canBecomeFirstResponder {
return YES;
}
Make the UIViewController
become first responder in viewDidAppear:
.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
If the view contains any element, such as a UITextField
, that might become first responder itself, ensure that element resigns first responder at some point. With a UITextField
, for example, the UIViewController
would need to implement the UITextFieldDelegate
protocol, and actually be the delegate. Then, in textFieldShouldReturn:
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
// Hides the keyboard
[theTextField resignFirstResponder];
// Returns first responder status to self so that shake events register here
[self becomeFirstResponder];
return YES;
}
Implement motionEnded:withEvent:
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if ( event.subtype == UIEventSubtypeMotionShake ) {
// Do something
}
if ([super respondsToSelector:@selector(motionEnded:withEvent:)]) {
[super motionEnded:motion withEvent:event];
}
}
There is a good post by Matt Drance of Apple in the iPhone Developer Forums (requires registration as a developer).
Update: implementing in a subclass of UIView
As discussed in the comments, this also works, not too surprisingly, in a subclass of UIView
. Here's how to construct a minimal example.
Create a new View-based Application project, call it ShakeTest
. Create a new subclass of UIView
, call it ShakeView
. Make ShakeView.h
look like this:
#import <UIKit/UIKit.h>
@interface ShakeView : UIView {
}
@end
Make ShakeView.m
look like this:
#import "ShakeView.h"
@implementation ShakeView
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if ( event.subtype == UIEventSubtypeMotionShake ) {
NSLog(@"Shake!");
}
if ([super respondsToSelector:@selector(motionEnded:withEvent:)]) {
[super motionEnded:motion withEvent:event];
}
}
@end
Make ShakeTestViewController.h
look like this:
#import <UIKit/UIKit.h>
#include "ShakeView.h"
@interface ShakeTestViewController : UIViewController {
ShakeView *s;
}
@end
Make ShakeTestViewController.m
look like this:
#import "ShakeTestViewController.h"
@implementation ShakeTestViewController
- (void)viewDidLoad {
[super viewDidLoad];
s = [[ShakeView alloc] init];
[[self view] addSubview:s];
[s becomeFirstResponder];
}
- (void)dealloc {
[s release];
[super dealloc];
}
@end
Build and run. Hit Cmd-Ctrl-Z to shake the iPhone simulator. Marvel at the log message.
Do you have the old method implemented? If you have the old application wide method implemented, you need to remove it before the new one will be called.
来源:https://stackoverflow.com/questions/1342674/motionbegan-not-working