如何在旋转之前检测iPhone的方向

12

在我的程序中,我根据旋转移动物体,但我并没有旋转整个视图。我使用的是:

  static UIDeviceOrientation previousOrientation = UIDeviceOrientationPortrait;

 - (void)applicationDidFinishLaunching:(UIApplication *)application {   
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];
    [[NSNotificationCenter defaultCenter] addObserver:self
           selector:@selector(didRotate:)
           name:@"UIDeviceOrientationDidChangeNotification" object:nil];

}

- (void) didRotate:(NSNotification *)notification{  
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

    [self doRotationStuff:orientation: previousOrientation];
previousOrientation = orientation;

} 

只要程序启动时设备方向为竖屏,这段代码就可以正常运行,但如果初始方向为横屏或倒置,则无法正常工作,因为[self doRotationStuff]会根据前一方向与当前方向的差异进行更改。是否有一种方法可以在启动时或旋转设备之前检测方向?

7个回答

12

根据您的情况,UIViewController类的interfaceOrientation属性可能是一个更简单的选择。在旋转之前使用此属性是正确的。


2
谢谢!我不知道那个领域存在 - 我一直在使用UIDevice的方向,但它并没有什么帮助。 - Chris
这就是为什么 *** S.O 真棒!*** ... 一直在疯狂地尝试解决一个 * 咳咳 * 简单的方向问题... 没有头绪... 搜索结果出现了 Delany 的答案。 - Howard Pautz

3

更新:

从评论讨论中可以看出,在首次发生方向变化之前,不能依赖于[UIDevice currentDevice].orientation。如果是这样,你可能可以通过获取原始的加速度计读数来进行修改。

#define kUpdateFrequency 30  // Hz
#define kUpdateCount 15 // So we init after half a second
#define kFilteringFactor (1.0f / kUpdateCount)

- (void)applicationDidFinishLaunching:(UIApplication *)app
{
    [UIAccelerometer sharedAccelerometer].updateInterval = (1.0 / kUpdateFrequency);
    [UIAccelerometer sharedAccelerometer].delegate = self;
    accelerometerCounter = 0;
    ...
}

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)accel
{
    // Average out the first kUpdateCount readings
    // acceleration_[xyz] are ivars typed float
    acceleration_x = (float)accel.x * kFilteringFactor + acceleration_x * (1.0f - kFilteringFactor);
    acceleration_y = (float)accel.y * kFilteringFactor + acceleration_y * (1.0f - kFilteringFactor);
    acceleration_z = (float)accel.z * kFilteringFactor + acceleration_z * (1.0f - kFilteringFactor);

    accelerometerCounter++;
    if (accelerometerCounter == kUpdateCount)
    {
        [self initOrientation];
        [UIAccelerometer sharedAccelerometer].delegate = nil;
    }
}

- (void)initOrientation
{
    // Figure out orientation from acceleration_[xyz] and set up your UI...
}

Translated response:

applicationDidFinishLaunching:期间,[UIDevice currentDevice].orientation是否返回正确的方向? 如果是,则可以根据该方向设置初始UI。

如果该属性直到稍后才设置,您可以尝试使用performSelector:afterDelay:在小延迟后初始化UI。

以下代码示例来自Kendall的答案,这里添加完整性:

[self performSelector:@selector(getOriented) withObject:nil afterDelay:0.0f];

我不确定零秒的延迟是否足够 - 这意味着 getOriented 的代码将在事件运行循环的第一次通过期间运行。您可能需要等待更长时间,以便加速度计读数在 UIDevice 上注册。


在 applicationDidFinishLaunching 中,[UIDevice currentDevice].orientation 是 UIDeviceOrientationUnknown。 - misty
我对如何使用performSelector:afterDelay毫无头绪。你能给一个代码示例吗? - misty
我尝试了你说的,但是即使使用 [self performSelector:@selector(getOriented) withObject:nil afterDelay:10.0f]; 也没有任何效果。 - misty
“没有任何效果”是什么意思?你的意思是在延迟后它仍然是UIDeviceOrientationUnknown吗?你可能需要在启动时调用[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]来确保方向得到更新。 - Daniel Dickison
是的,我的意思是即使延迟后,它仍然是UIDeviceOrientationUnknown。[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications] 在- (void)applicationDidFinishLaunching:(UIApplication *)application { }中被调用。您是否建议我需要更早地激活它? - misty
似乎不能仅依靠UIDevice的方向属性,直到方向实际改变才能使用。这可能很糟糕(您可能需要向苹果提交错误/增强请求)。同时,您可以注册原始加速度计通知并通过这种方式进行修改(也许等待10个快速更新并以此为基础确定初始方向)。 - Daniel Dickison

1
Mort,这些答案似乎有点离题;我不明白为什么你不能使用UIViewController类的以下内置方法:
-(void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {}

这个方法会在旋转发生后自动调用(而不是像shouldAutorotateToInterfaceOrientation一样只告诉你它即将发生)。方便的是,变量'fromInterfaceOrientation'包含了之前的方向。正如文档所说,你可以假设视图的interfaceOrientation属性已经被设置为新的方向,因此你就有了一个方法可以访问旧的方向和新的方向!

如果我漏掉了什么,而你已经放弃使用这个方法,那我道歉!只是看起来很奇怪,你正在创建和存储一个“先前方向”的变量,而上面的方法已经免费提供了。

希望能帮到你!


如果我打算旋转界面,那么这个方法是可行的,但我并不想这样做。 - misty

1
这是一种在应用程序首次加载时获取方向并且 UIDeviceOrientation 设置为 UIDeviceOrientationUnknown 的方法。您可以查看旋转视图的 transform 属性。
if(toInterface == UIDeviceOrientationUnknown) {
    CGAffineTransform trans = navigationController.view.transform;
    if(trans.b == 1 && trans.c == -1)
        toInterface = UIDeviceOrientationLandscapeLeft;
    else if(trans.b == -1 && trans.c == 1)
        toInterface = UIDeviceOrientationLandscapeRight;
    else if(trans.a == -1 && trans.d == -1)
        toInterface = UIDeviceOrientationPortraitUpsideDown;
    else
        toInterface = UIDeviceOrientationPortrait;
}

这真是太棒了!它将为您提供视图的方向。我使用它与UIDeviceOrientationDidChangeNotification一起来检测我的先前方向。 - cnotethegr8

1

如果您需要确定指向的方向,请使用此选项来定位UI。

我不是100%确定这是否正确,但是根据我的经验:

[[[UIApplication sharedApplication] statusBar] orientation]

0

如需了解如何从加速度计读数中获取设备方向的更完整示例,请单击此处。 由于该解决方案依赖于加速度计读数,因此它无法在模拟器上运行,因此您必须在设备上工作...我仍在寻找适用于模拟器的解决方案。


-1
作为回应您的评论,我认为在这里放置代码比在评论中更好(虽然真正的功劳应该归于Daniel):
在applicationDidFinishLaunching:中:
[self performSelector:@selector(getOriented) withObject:nil afterDelay:0.0f];

然后你只需要调用这个方法:

- (void) getOriented 
{ 
   UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
   // save orientation somewhere
}

我尝试了你说的,但是即使使用 [self performSelector:@selector(getOriented) withObject:nil afterDelay:10.0f]; 也没有任何效果。 - misty
十秒钟后它被称为什么方向?似乎在十秒钟后,方向应该被设置...或者在那个时候,只需询问主视图控制器它的方向是什么。 - Kendall Helmstetter Gelner
它是UIDeviceOrientationUnknown。 - misty

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接