Shake Gesture detection in UIWindow subclass takes over default text undo manager
What I want is having my iPhone app aware of shaking gesture all the time except when an开发者_如何学Pythony UITextfield
or UITextview
become firstResponder.
(I followed this: https://stackoverflow.com/questions/150446/how-do-i-detect-when-someone-shakes-an-iphone/1351486#1351486I)
I subclass UIWindow
and implemented motionEnded:withEvent:
method and it works even if I set a UITextView
to be firstResponder. My custom UIWindow
calls motionEnded:withEvent:
even if it's not firstResponder.
So the problem is my UItextView
's default undo manager does not respond to shaking anymore. The UIWindow
takes over all the handling of Shake-Gesture regardless of how the view-hierarchy or firstResponders have been changed.
Could anyone shed some light on how to temporarily disable UIWindow's detection or have the current firstResponder takes over the Shaking-Gesture based on the implementation I have?
Thanks in advance!
Anyway I found a solution.
The default undo manager is actually still there saving all actions done to a UITextView secretly.
Since UIWindow
takes over the motion handling, first I try to take it back by overriding motionEnded:withEvent:
in the viewController that contains my UITextView
.
Second, get the undoManager by [myTextView undoManager]
then you can send undo
or redo
messages to it.
Now to mimic the default undo manager alertview, use redoMenuItemTitle
and undoMenuItemTitle
to get button title, then use canUndo
and canRedo
to decide whether to show button or not.
Edit: Here's the code from my application:
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.type == UIEventTypeMotion && event.subtype == UIEventSubtypeMotionShake) {
//textUndoManager is an ivar but it was just a reference to the undoManager
//textUndoManager = [myTextView undoManager]; <--- in viewDidLoad:
NSString *undoButtonTitle = nil;
NSString *redodoButtonTitle = nil;
NSString *alertViewTitle = nil;
if ([textUndoManager canUndo])
undoButtonTitle = [NSString stringWithString:[textUndoManager undoMenuItemTitle]];
if ([textUndoManager canRedo])
redodoButtonTitle = [NSString stringWithString:[textUndoManager redoMenuItemTitle]];
if (!undoButtonTitle && !redodoButtonTitle)
alertViewTitle = @"Nothing to Undo";
UIAlertView *alertView;
if (undoButtonTitle == nil) {
alertView = [[UIAlertView alloc] initWithTitle:alertViewTitle message:nil delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:redodoButtonTitle, nil];
} else {
alertView = [[UIAlertView alloc] initWithTitle:alertViewTitle message:nil delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:undoButtonTitle, redodoButtonTitle, nil];
}
[alertView show];
}
}
//UIAlertViewDelegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if ([[alertView buttonTitleAtIndex:buttonIndex] isEqualToString:[textUndoManager undoMenuItemTitle]]) {
[textUndoManager undo];
}
if ([[alertView buttonTitleAtIndex:buttonIndex] isEqualToString:[textUndoManager redoMenuItemTitle]]) {
[textUndoManager redo];
}
}
精彩评论