旋转设备时是不是可以对 UIView 使用自定义旋转?

Posted

技术标签:

【中文标题】旋转设备时是不是可以对 UIView 使用自定义旋转?【英文标题】:Is it possible to use custom rotation for UIView when rotating device?旋转设备时是否可以对 UIView 使用自定义旋转? 【发布时间】:2014-12-09 02:27:20 【问题描述】:

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

我已经“成功”创建了这个。我只允许风景。打开后是这样的:

Figure 1

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

当将视图旋转到另一侧时,每个元素都会围绕自己旋转以显示这一点(相机除外):

Figure 2

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

这样做的问题是整个视图会旋转,因此屏幕总是会显示Figure 1,而“设备顶部”会改变方向。

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

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

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

问题:

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

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

【问题讨论】:

隐藏状态栏吗? 【参考方案1】:

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

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

【讨论】:

以上是关于旋转设备时是不是可以对 UIView 使用自定义旋转?的主要内容,如果未能解决你的问题,请参考以下文章

当设备方向更改 SWIFT 5 时重绘自定义 UIVIEW

iOS Objective C - 旋转回纵向后 UIView 无法正确显示

旋转没有动画的自定义 UIView

如何将 UIView 调整为横向?

更改设备方向时重绘自定义 uiview

以编程方式创建UIView,在旋转设备时保留其大小