Reputation: 8502
I've never had this happen before and can't figure out what's going on. I suspect it might be auto-layout, but I don't see how. I have a "Compass" view that has several subviews it manages itself (not part of auto layout). Here's an example of their setup:
- (ITMView *) compass {
if (!_compass){
_compass = [ITMView new];
_compass.backgroundColor = [UIColor blueColor];
_compass.layer.anchorPoint = CGPointMake(.5, .5);
_compass.translatesAutoresizingMaskIntoConstraints = NO;
_compass.frame = self.bounds;
__weak ITMCompassView *_self = self;
_compass.onDraw = ^(CGContextRef ref, CGRect frame) { [_self drawCompassWithFrame:frame]; };
[self addSubview:_compass];
}
return _compass;
}
I need to rotate the compass in response to heading changes:
- (void) setCurrentHeading:(double)currentHeading{
_currentHeading = fmod(currentHeading, 360);
double rad = (M_PI / 180) * _currentHeading;
self.compass.transform = CGAffineTransformMakeRotation(rad);
}
The problem is that it's rotating in on the z-axis for some reason:
I'm not manipulating layer transforms on any other views. Does anyone have any idea why this is occurring?
I checked the transform for all superviews. Every superview has an identity transform.
I logged the transform of the compass view before and after it was set for the first time. Before it was set, the transform was at identity, which is expected. After I set the transform to rotate 242.81
degrees (4.24
rad) I get:
[
-0.47700124155378526, -0.87890262006444575,
0.87890262006444575, -0.47700124155378526,
0, 0
]
I checked CATransform3DIsAffine
and it always returns YES
. I double checked the layer transform and for a rotation of 159.7
(degrees) I get:
[
-0.935, 0.356, 0, 0,
-0.356, -0.935, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
]
That looks correct to me.
All of the transforms are correct but it's still not displaying correctly on screen.
I removed my drawing code from the view and set the view background to blue. The view is definitely being rotated, squeezed, or something:
Some things to note:
Upvotes: 1
Views: 549
Reputation: 8502
I'm not sure why @matt withdrew his answer, but he was correct: The compass view had it's frame reset every time I made a rotation in the layoutSubviews
method in my containing superview. I wasn't expecting this, thinking that a rotation wouldn't trigger a layoutSubviews
. The frame never changed, but the applied transform distorted the results as the frame was re-applied to the view. What threw me was the results really looked like the view was being rotated in 3D, which led me down that particular rabbit hole. At least I know what to look for now.
Something I want to point out: The apparent 3D rotation was very particular. It rotated around each diagonal combination of {x,Y} sequentially between each 90° quadrant of the unit circle. This makes sense if you think about how the frame would distort over those periods.
The solution is simple enough, store and remove the transform before setting the subview frame and then reapply the transform. However, because the rotation is applied very, very frequently (inside an animation block no less) I added an escape to help reduce the load:
- (void) layoutSubviews{
[super layoutSubviews];
if (!CGRectEqualToRect(_lastLayout, self.bounds)){
CGRect frame = SquareRectAndPosition(self.bounds, CGRectXCenter, CGRectYCenter);
CGAffineTransform t;
t = self.compass.transform;
self.compass.transform = CGAffineTransformIdentity;
self.compass.frame = frame;
self.compass.transform = t;
t = self.target.transform;
self.target.transform = CGAffineTransformIdentity;
self.target.frame = frame;
self.target.transform = t;
}
_lastLayout = self.bounds;
}
Upvotes: 1