14
votes

So I need to apply some scaling and some rotation to a view (I do this using gestures), so for each gesture I update the current scalling and rotation values with something like:

self.scaleWidth *= gesture.scale; //When I detect an horizontal pinch
self.scaleHeight *= gesture.scale; //When I detect a vertical pinch
self.rotationAngle += gesture.rotationAngle; //When I detect a rotation

Then I do the following to transform the view:

CGAffineTransform transform = CGAffineTransformScale(CGAffineTransformIdentity, self.scaleWidth, self.scaleHeight);
self.theSubViewToTransform.transform = CGAffineTransformRotate(transform, self.rotationAngle);

When I only do scaling, it works fine. When I do scaling then rotate, it rotates fine. When after rotating I try to scale again, it doesn't work fine: the scale is applied as if done after the rotation, deforming my image structure.

I thought I did what needed to be done to avoid this: starting each time from an identity transform, scaling first then rotating, but obviously I was wrong...

Does any one know what's wrong with my implementation ?

Thanks

4

4 Answers

15
votes

If you start with the identity transform every time, the end result you are setting the subview's transform to will only include the scaling and rotation from the current gesture. Instead of starting with the identity, start with the current transform of the view.

CGAffineTransform transform = self.theSubViewToTransform.transform;
transform = CGAffineTransformScale(transform, self.scaleWidth, self.scaleHeight);
transform = CGAffineTransformRotate(transform, self.rotationAngle);
self.theSubViewToTransform.transform = transform;

The first time this executes, the transform will start out as the identity transform. On subsequent executions, it will make the new changes on top of the old ones.

6
votes

For swift 3:

view.transform = CGAffineTransform(rotationAngle:  CGFloat.pi).concatenating(CGAffineTransform(scaleX: 0.4, y: 0.4))
3
votes

You should start from your current transformed state and apply transformation which is expected. Also you can have a look at CGAffineTransformConcat, it will make it a single transform before applying.

CGAffineTransform transform = yourView.transform;
transform = CGAffineTransformConcat(CGAffineTransformScale(transform,  self.scaleWidth, self.scaleHeight),
                                    CGAffineTransformRotate(transform, self.rotationAngle));
yourView.transform = transform;

Hope it helps!

2
votes

Try applying the transformations to the identity transform, e.g.

CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformScale(transform, scaleWidth, scaleHeight);
transform = CGAffineTransformRotate(transform, angle);
viewToTransform.transform = transform;