旋转设备时是否可以为UIView使用自定义旋转?

时间:2014-12-09 02:27:21

标签: ios objective-c uiview rotation uiinterfaceorientation

我正在为我的应用程序创建一个camera-viewController,我想使用与iOS默认相机应用程序相同的想法:记录按钮始终位于设备的同一侧。内容只是用自己的轴旋转,而不是整个屏幕翻转。

我已经“成功”创造了这个。我只允许风景。打开它时看起来像这样:

Figure 1

      <- top of device
------------------------------
| -------------------        |
||                   |       |
||                   |  ---  |
||    camera-view    | | ^ | |
||                   |  ---  |
||                   |       |
| -------------------        |
-----------------------------

将视图旋转到另一侧时,每个元素都会自动旋转以显示此信息(相机除外):

Figure 2

       top of device ->
------------------------------
|        ------------------- |
|       |                   ||
|  ---  |                   ||
| | ^ | |    camera-view    || [top of device ->]
|  ---  |                   ||
|       |                   ||
|        ------------------- |
-----------------------------

问题在于整个视图会旋转,因此屏幕始终会显示Figure 1,而“设备顶部”会改变方向。

通过在NO中返回-(BOOL)shouldAutorotate,我得到了我想要的结果,尽管一切都会颠倒过来,自然而然。 然后,通过注册设备方向规范,并使用我自己的选择器,我可以使用例如[btnRecord setTransform:CGAffineTransformMakeRotation(-M_PI)];

以编程方式旋转每个控件(例如按钮,文本等)

在旋转时将Transform设置为每个控件,同时阻止控制器实际旋转,我得到了我想要的结果。有点。

问题:

当使用我上面描述的方法时,我在视觉上得到了正确的结果,但我怀疑我应该用另一种方式来管理。当我收到来自其他应用程序(例如Mail,Facebook等)的通知时,它们将始终以原始方向显示。这是有道理的。如果此viewController在LandscapeLeft中启动,然后转向LandscapeRight,则我的所有控件和整个视图都将为该方向设置动画并且看起来很完美,但传入通知将在屏幕底部显示为倒置。这当然是我在NO中返回shouldAutorotate的结果。

在默认的Camera-app中,他们已经完成了它,所以它必须是可能的。 有没有办法启用自动旋转,但同时阻止控制器的视图实际旋转?我当时唯一能想到的解决方案是创建一个动画,它可以完美地抵消旋转动画,让它保持晃动,但这听起来很糟糕,我想找到一个更好的方法。

1 个答案:

答案 0 :(得分:0)

您可以使用加速度计检测应用程序的激活方向:

- (void)applicationWillEnterForeground:(UIApplication*)application {

    // [motionManager stopAccelerometerUpdates] doesn't stop
    // all gathered accelerometer data, but we want trigger it once.
    static BOOL read = NO;
    // applicationWillEnterForeground will happen lot of times :-)
    read = NO;

    CMMotionManager* motionManager = [[CMMotionManager alloc]init];

    [motionManager
        startAccelerometerUpdatesToQueue:
            [[NSOperationQueue alloc] init]
        withHandler:
            ^(CMAccelerometerData* data, NSError* error) {
                if (!read) {
                    read = YES;
                    [motionManager stopAccelerometerUpdates];

                    CGFloat accx = data.acceleration.x;
                    CGFloat accy = data.acceleration.y;

                    dispatch_async(
                        dispatch_get_main_queue(),
                        ^{
                            [[UIApplication sharedApplication]
                                setStatusBarOrientation:
                                    deviceOrientationFromAcceleration(accx, accy)
                                animated:NO];
                        });
                    }
            }];
}

deviceOrientationFromAcceleration()函数定义为

int deviceOrientationFromAcceleration(CGFloat x, CGFloat y) {
    // Get the current device angle
    float xx = -x;
    float yy = y;
    float angle = atan2(yy, xx);

    if (angle >= -2.25f && angle <= -0.75f) {
        return UIInterfaceOrientationPortrait;
    }
    else if (angle >= -0.75f && angle <= 0.75f) {
        return UIInterfaceOrientationLandscapeRight;
    }
    else if (angle >= 0.75f && angle <= 2.25f) {
        return UIInterfaceOrientationPortraitUpsideDown;
    }
    else if (angle <= -2.25f || angle >= 2.25f) {
        return UIInterfaceOrientationLandscapeLeft;
    }

    return 0;
}