views:

112

answers:

1

What I want is having my iPhone app aware of shaking gesture all the time except when any UITextfield or UITextview become firstResponder.

(I followed this: http://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!

A: 

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];
    }
}
Matt Chuang