3

I have a UIView selectFrame with four corner handles as subviews. Each corner handle has a UIPanGestureRecognizer which calls this method:

This is my code (where self is the selectFrame UIView):

-(void)handleDrag:(UIPanGestureRecognizer *)gesture

{
    UIView *view = gesture.view;
    CGPoint translation = [gesture translationInView:view.superview];

    CGRect frame = self.bounds;

    switch (view.tag) {
        case (DRAG_HANDLE_TAG):  //upper left
            frame.size.width -= translation.x;
            frame.size.height -= translation.y;
            break;
        case (DRAG_HANDLE_TAG+1): //upper right
            frame.size.width += translation.x;
            frame.size.height -= translation.y;
            break;
        case (DRAG_HANDLE_TAG+2): //bottom left
            frame.size.width -= translation.x;
            frame.size.height += translation.y;
            break;
        case (DRAG_HANDLE_TAG+3): //bottom right
            frame.size.width += translation.x;
            frame.size.height += translation.y;
            break;
    }
    self.bounds = CGRectIntegral(frame);

    CGAffineTransform transform = self.transform;
    transform = CGAffineTransformTranslate(transform, translation.x/2, translation.y/2);
    self.transform = transform;

    [gesture setTranslation:CGPointZero inView:view.superview];

}

This code works really well without a rotation, but with the UIView rotated, it drifts.

However, if I do the whole calculation at the end of the gesture, by putting

if (gesture.state != UIGestureRecognizerStateEnded)
    return;

at the top of the method, it works well even with the rotation, so it seems that the code works, but could it be rounding errors?

This question seems to have been asked in many different guises, but I can't find, after many hours of looking, one exactly answered. There are a number of StickerView examples available that resize from the center. This question Resize UIView While It Is Rotated with Transform receives a very full answer, but it doesn't really answer the question.

Edit: There are a lot of responses suggesting trigonometry, and I have attempted this, but it seems to me that it should be possible simply using CGAffineTransforms. I have experimented with this, but with no good result.

Community
  • 1
  • 1
Caroline
  • 4,875
  • 2
  • 31
  • 47
  • Not yet - I got sidetracked, but will get back to it eventually. Hopefully learning some linear algebra will help! – Caroline Sep 06 '14 at 03:12

2 Answers2

3

I've put up a project on github to move, rotate and scale. It only uses CGAffineTransforms for the rotation. This project has drag handles at the corners of the view, and resizes from the opposite corners and a rotate handle.

It uses Erica Sadun's article Taking Charge of UIView Transforms in iOS Programming and Brad Larson's / Magnus's anchor point code.

Link to my Resizable project: https://github.com/carolight/Resizable

Community
  • 1
  • 1
Caroline
  • 4,875
  • 2
  • 31
  • 47
2

We also had a problem in accumulating different transformations. Only translation or only scaling or only rotation would work well. But, if I rotated after translation or vice versa, then either the rotation would rotate the view around parent view's 0, 0 and scaling would drift the image as mentioned in your question.

Following two things solved our problem:

  1. For each of these gestures, we set anchor point to 0.5, 0.5 for the view we are rotating, if the state is UIGestureRecognizerStateBegan.

    view.layer.anchorPoint = CGPointMake(0.5, 0.5)

  2. When we translate or scale, we get the view's current transformation, concat it with new (scaling/translation) transformation as follows: CGAffineTransformConcat(currentTransformation, newTransformation)

    However, in case of rotation we concat with newTransformation first and currentTransformation as second parameter, as follows: CGAffineTransformConcat(newTransformation, currentTransformation)

Please note closely that the order we pass the transformation to be concatenated is important, as mentioned in documentation of CGAffineTransformConcat

Also, read this to understand anchorPoint better, and this for why it might be related to you problem.

Community
  • 1
  • 1
Ozair Kafray
  • 13,351
  • 8
  • 59
  • 84