CGAffineTransformMakeRotation以3D旋转

时间:2015-02-07 17:47:26

标签: ios uiview rotation cgaffinetransform

我以前从来没有这样做过,也无法弄清楚发生了什么。我怀疑它可能是自动布局,但我不知道如何。我有一个" Compass"视图,它有自己管理的几个子视图(不是自动布局的一部分)。以下是他们设置的示例:

- (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;
}

我需要旋转罗盘以响应航向变化:

- (void) setCurrentHeading:(double)currentHeading{
    _currentHeading = fmod(currentHeading, 360);
    double rad = (M_PI / 180) * _currentHeading;
    self.compass.transform = CGAffineTransformMakeRotation(rad);
}

问题在于它出于某种原因在z轴上旋转:

enter image description here

我没有在任何其他视图上操纵图层变换。有谁知道为什么会这样?

更新

我检查了所有超级视图的转换。每个超级视图都有一个身份变换。

我在第一次设置之前和之后记录了罗盘视图的变换。在它被设定之前,转变是在身份,这是预期的。在我将变换设置为旋转242.81度(4.24 rad)后,我得到:

[
  -0.47700124155378526, -0.87890262006444575, 
  0.87890262006444575, -0.47700124155378526, 
  0, 0
]

更新2

我检查了CATransform3DIsAffine,它总是返回YES。我仔细检查了图层变换,并且我得到了159.7(度)的旋转:

[
 -0.935,  0.356,   0, 0, 
 -0.356, -0.935,   0, 0, 
  0,      0,       1, 0, 
  0,      0,       0, 1
]

这对我来说是正确的。

所有变换都是正确的,但无法在屏幕上正确显示。

更新3

我从视图中删除了我的绘图代码,并将视图背景设置为蓝色。视图肯定是旋转,挤压或其他东西:

enter image description here

有些注意事项:

  • 视图在90,180,270& 0度。
  • 视图在45,135,225和15处消失(转向边缘) 315度。
  • 视图看起来就像它在从0度旋转到360度时在3D中旋转一样。

1 个答案:

答案 0 :(得分:1)

我不确定为什么@matt撤回了他的答案,但他是正确的:每次我在我的包含超视图中的layoutSubviews方法中进行旋转时,罗盘视图都会重置帧。我没想到这一点,认为轮换不会触发layoutSubviews。帧永远不会改变,但是当帧重新应用于视图时,应用的变换会使结果失真。让我印象深刻的是结果真的看起来就像视图在3D中旋转一样,这让我陷入了那个特殊的兔子洞。至少我知道现在要找什么。

我想指出的一点:明显的3D旋转非常特别。它在单位圆的每个90°象限之间顺序地围绕{x,Y}的每个对角线组合旋转。如果您考虑帧在这些时段内如何扭曲,这是有道理的。

解决方案很简单,在设置子视图帧之前存储和删除变换,然后重新应用变换。但是,因为非常频繁地应用旋转(在动画块内部也不少),我添加了一个转义来帮助减少负载:

- (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;
}