ios - CGAffineTransformMakeRotation 在 3D 中旋转

标签 ios uiview rotation cgaffinetransform

我以前从未遇到过这种情况,无法弄清楚发生了什么。我怀疑它可能是自动布局,但我不知道如何。我有一个“指南针” View ,它有几个它自己管理的 subview (不是自动布局的一部分)。这是他们的设置示例:

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

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

更新

我检查了所有 super View 的转换。每个父 View 都有一个身份转换。

我记录了第一次设置罗盘 View 前后的变化。在它被设置之前,转换是在 identity,这是预期的。在我将变换设置为旋转 242.81 度(4.24 弧度)后,我得到:

[
  -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

我从 View 中删除了绘图代码并将 View 背景设置为蓝色。 View 肯定在旋转、挤压或其他情况:

enter image description here

一些注意事项:

  • View 可正确显示 90、180、270 和 0 度。
  • View 在 45、135、225 和 315 度时消失(在边缘打开)。
  • View 看起来在从 0 度到 360 度的过程中以 3D 方式旋转。

最佳答案

我不确定为什么 @matt 撤回了他的回答,但他是正确的:每次我在包含 super View 的 layoutSubviews 方法中进行旋转时,罗盘 View 都会重置其框架。我没想到会这样,认为旋转不会触发 layoutSubviews。框架从未改变,但应用的变换扭曲了结果,因为框架被重新应用到 View 。令我震惊的是,结果确实看起来 View 在 3D 中旋转,这让我陷入了那个特别的兔子洞。至少我知道现在要寻找什么。

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

解决方案很简单,在设置 subview 框架之前存储和删除变换,然后重新应用变换。然而,因为旋转应用得非常非常频繁(在动画 block 内)我添加了一个转义符来帮助减少负载:

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

关于ios - CGAffineTransformMakeRotation 在 3D 中旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28385371/

相关文章:

ios - 在 Swift 中转换 UTC 时间

ios - 自定义按钮回推

uiview - 如何在 Swift 中的主视图中添加 subview

ios - 如何在 ViewController 中将 AVPlayer 添加到 UIView

ios - 将 CGRectMake (x,x,x,x) 更改为不同的位置,例如 (y,y,y,y)

ios - Swift 管理内存

ios - 当我的 ViewController 被导航时,AFURLSessionManager 应用程序崩溃了

ios - 旋转手势结束后继续旋转图像

java - 为什么这段代码只旋转正方形?

ios - 数组值更改后,UiTableview 值未更新