Alexandre
Alexandre

Reputation: 817

Applying scaling and rotation on a view using CGAffineTransform

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

Upvotes: 14

Views: 23278

Answers (4)

UnRewa
UnRewa

Reputation: 2472

For swift 3:

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

Upvotes: 7

NeverHopeless
NeverHopeless

Reputation: 11233

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!

Upvotes: 3

Ryan
Ryan

Reputation: 5496

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;

Upvotes: 2

RPeck
RPeck

Reputation: 448

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.

Upvotes: 17

Related Questions