简体   繁体   中英

Rotating custom UIView with no animation

I have a compass dial drawn in drawRect and I want to avoid redrawing it, but rotate it instead as heading compass heading changes. When I use CABasicAnimation like this:

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
animation.fromValue = [NSNumber numberWithFloat:_dialAngle*M_PI/180];
animation.toValue = [NSNumber numberWithFloat:dialAngle*M_PI/180];
animation.duration = 0.0;
animation.repeatCount = 0;
animation.removedOnCompletion = false;
animation.fillMode = kCAFillModeForwards;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[dial.layer addAnimation:animation forKey:@"transform.rotation.z"];

it rotates as expected (red arrow on top and text are different view from the compass dial):

在此处输入图片说明

I don't really want to animate, so I used variants like:

[dial.layer setValue:[NSNumber numberWithDouble: dialAngle*M_PI/180] forKeyPath:@"transform.rotation.z"];

Or:

dial.transform = CGAffineTransformMakeRotation(arrowAngle*M_PI/180);

Or:

CATransform3D t = CATransform3DIdentity;

dial.layer.transform = CATransform3DRotate(t, dialAngle*M_PI/180, 0.0, 0.0, 1.0);

And they all lead to the same skewed result:

在此处输入图片说明

Autolayout and constraints are not present on this view.

I should be missing something and I can't figure our what it is. What am I missing to get the same result as with the animation?

Also, from your experience, should I really use rotate transformation in favor of drawRect? In profiler I saw that drawRect was taking quite a few cpu cycles. When I use transforms I don't see "my" cpu cycles, but total CPU values are just about the same when I rotate intensively.

It would be great to tame the transforms with your help :)!

After banging my head against the wall and looking into the .transform values on the view I found out that the problem was in setting .frame for the view in layoutSubviews. When using only bounds and center:

dial.bounds = self.bounds;
dial.center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));

It worked correctly with all of the transformation options mentioned in the question.

Turns out this is a well-known fact that you should not touch the frame if you have a non identity transform set on a view ( docs ).

However, if the transform property contains a non-identity transform, the value of the frame property is undefined and should not be modified. In that case, you can reposition the view using the center property and adjust the size using the bounds property instead.

Also be sure not to use .frame of the transformed view anywhere else. I was using it in drawRect as .frame.size and of course had to change it to .bounds.size.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM