4

I'm just using a simple

self.customerTextField.text = @"text";

but I would like there to be undo support, where if they shake the phone they can undo the change.

I'm kinda at a loss as to how to accomplish this. All the exapmles I find are for UITextView.

======================== Current iteration of code ======================

-(void)getUniqueItemID {

    [self.inventoryLibrarian generateUniqueItemIDwithCompletionBlock:^(NSString *string) {

        [self undoTextFieldEdit:string];
        //self.customTextField.text = string;

    }];

}

- (void)undoTextFieldEdit: (NSString*)string
{
    [self.undoManager registerUndoWithTarget:self
                                    selector:@selector(undoTextFieldEdit:)
                                      object:self.customTextField.text];
    self.customTextField.text = string;
}

-(BOOL)canBecomeFirstResponder {
    return YES;
}
Hackmodford
  • 3,901
  • 4
  • 35
  • 78
  • Check this http://stackoverflow.com/questions/150446/how-do-i-detect-when-someone-shakes-an-iphone to detect shake gesture and then implement undo feature yourself with that – iDev Jan 12 '13 at 04:05

2 Answers2

4

Shake-to-undo
Put this line in your appDelegate's application:didFinishLaunchingWithOptions: method:

    application.applicationSupportsShakeToEdit = YES;

and in the relevant viewController.m

    -(BOOL)canBecomeFirstResponder {
        return YES;
    }

the rest of this code goes in viewController.m

Property
Put this in the class extension...

    @interface myViewController()
    @property (weak, nonatomic) IBOutlet UITextField *inputTextField;
    @end

link it up to your text field in Interface Builder.

Undo method
Adds an invocation of itself to the redo stack

    - (void)undoTextFieldEdit: (NSString*)string
    {
        [self.undoManager registerUndoWithTarget:self
                                        selector:@selector(undoTextFieldEdit:)
                                          object:self.inputTextField.text];
        self.inputTextField.text = string;
    }

(we do not need to create an NSUndoManager instance, we inherit one from the UIResponder superclass)

Undo actions
Not required for shake-to-undo, but could be useful...

    - (IBAction)undo:(id)sender {
        [self.undoManager undo];
    }
    - (IBAction)redo:(id)sender {
        [self.undoManager redo];
    }

Invocations of the undo method
Here are two different examples of changing the textField's contents…

Example 1
Set the textField's contents from a button action

    - (IBAction)addLabelText:(UIButton*)sender {
        [self.undoManager registerUndoWithTarget:self
                                        selector:@selector(undoTextFieldEdit:)
                                          object:self.inputTextField.text];
        self.inputTextField.text = @"text";
    }

Risking loss of clarity, we can shorten this to:

    - (IBAction)addLabelText:(UIButton*)sender {
        [self undoTextFieldEdit: @"text"];
    }

as the undoManager invocation is the same in both methods

Example 2
Direct keyboard input editing

    #pragma mark - textField delegate methods

    - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
    {
        [self.undoManager registerUndoWithTarget:self
                                        selector:@selector(undoTextFieldEdit:)
                                          object:textField.text];
        return YES;
    }

    - (BOOL)textFieldShouldReturn:(UITextField *)textField
    {
        //to dismiss the keyboard
        [textField resignFirstResponder];
        return YES;
    }
foundry
  • 31,615
  • 9
  • 90
  • 125
  • I tried this but it didn't work. Maybe it's because the viewController is a UITableViewCell? I added the code I've used so far. And I also did add the shaketoedit to the appDelegate. When I add the "canBecomeFirstResponder" it no longer supports shake to undo for the cell. – Hackmodford Jan 16 '13 at 14:46
  • @Hackmodford: "Maybe it's because the viewController is a UITableViewCell?" ...that sounds a little... impossible... do you mean, the _textField_ is in a table view cell? Or do you mean that you have a viewController that controls the contentView of each tableViewCell? Or...? – foundry Jan 17 '13 at 05:57
  • @Hackmodford, I have tested this code with the textField inside a `UITableViewCell` in a static table. It just works. All of the code that is not in the App Delegate is in the `TableViewController`. The textField has to have two connections to the `TableViewController` - (1) `delegate` is the TableVC; (2) IBOutlet is `self.inputTextField` (or in your case `customTextField`). `canBecomeFirstResponder` is in the TableViewController and works fine. – foundry Jan 17 '13 at 13:54
  • I have a custom uitableviewcell setup with a nib. My code for changing the textfield is in the uitableviewcell's class file. I tried setting customcell.m as the delegate for the textfield. But it didn't make a difference. canbecomefirstresponder is never called as far as I can tell – Hackmodford Jan 17 '13 at 14:27
  • I got it working in the tableviewcell controller. I just had to call [self becomefirstresponder]; just before changeing the text in the text field. Now it works. Thanks! – Hackmodford Jan 17 '13 at 14:55
  • @Hackmodford, that's great you have it working now. I trust you'll be awarding the bonus...;-j – foundry Jan 19 '13 at 06:50
0

You don't need to do anything, it just works unless you disable it. See this question for example.

Community
  • 1
  • 1
JefferyRPrice
  • 895
  • 5
  • 17
  • I just realized you might mean the user action that changed the text was not necessarily an edit with the keyboard but the result of something programmatic, in which case my answer is a bit useless. – JefferyRPrice Jan 12 '13 at 00:56
  • I think the OP was after the programatic details, but it's nice to be reminded that it works out of the box for user actions too. – Benjohn Dec 09 '14 at 06:14