4

How to use NSUndoManager to rotate a UIImageView using rotation gesture? This is my code for rotation.

- (void)handleRotate:(UIRotationGestureRecognizer *)recognizer 
{
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        prevRotation = 0.0;
    } 

    float thisRotate = recognizer.rotation - prevRotation;
    prevRotation = recognizer.rotation;
    recognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform, thisRotate);

    CGPoint lastpoint = point;
}
Costique
  • 23,712
  • 4
  • 76
  • 79
Prerna chavan
  • 3,179
  • 7
  • 35
  • 77

1 Answers1

4

First of all, read “Using Undo on iPhone”. Make sure you have set the undoManager property somewhere in your responder chain (probably in your view controller).

We only want to push an undo action when the gesture ends. But when we push the undo action, we need to know the view's transform when the gesture started. Create an instance variable to hold that original transform:

@implementation YourViewController {
    CGAffineTransform _originalImageViewTransform;
}

Next, we need a method that pushes an undo action and sets the view's transform:

- (void)setTransform:(CGAffineTransform)newTransform ofView:(UIView *)view
    undoTransform:(CGAffineTransform)undoTransform
{
    // If I'm called because the gesture ended, this pushes an undo action.
    // If I'm called because the user requested an undo, this pushes a redo action.
    [[self.undoManager prepareWithInvocationTarget:self]
        setTransform:undoTransform ofView:view undoTransform:newTransform];

    // Now actually set the transform.
    view.transform = newTransform;
}

Your handleRotate: method needs to detect the state of the gesture and take the appropriate action.

- (void)handleRotate:(UIRotationGestureRecognizer *)recognizer {
    UIView *view = recognizer.view;
    UIGestureRecognizerState state = recognizer.state;

    if (state == UIGestureRecognizerStateCancelled) {
        view.transform = _originalImageViewTransform;
        return;
    }

    if (state == UIGestureRecognizerStateBegan) {
        _originalImageViewTransform = view.transform;
    }

    CGAffineTransform transform = view.transform;
    transform = CGAffineTransformRotate(transform, recognizer.rotation);
    recognizer.rotation = 0; // This line means we don't need prevRotation

    if (state == UIGestureRecognizerStateEnded) {
        [[ The gesture ended, so push an undo action before setting the transform.
        [self setTransform:transform ofView:view undoTransform:_originalImageViewTransform];
    } else {
        // The gesture changed but didn't end, so don't push an undo action.
        view.transform = transform;
    }
}
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • But if user rotates it 100 times then undo redo function will not get properly worked. User will have to press undo for 100 times to rotate it to original position. So i want to set undo manager only for uigesturerecogniserstateended. HOw to do that. – Prerna chavan Feb 06 '12 at 05:29
  • I like it though I have Many propertied I need to undo. _RE:"Create an instance variable to hold that original transform"_ I can see that for just the Rotation gesture, but what if you implement Pan, Rotate, Pinch, Border color, Shadow, Property A, ...Property Z. Seems like Having iVars for each that are set at the beginning of a change might get out of control? – scooter133 Mar 19 '12 at 21:32