UINavigationController工具栏和设备方向(旋转)

时间:2010-10-03 02:04:53

标签: iphone uinavigationcontroller uitoolbar autorotate autoresizingmask

所以我有这个iPhone应用程序,嵌套设置如下: [RootViewController的] - GT;的UITabBarController] - GT;的UINavigationController] - GT; [subViewControllers]。一切都是以编程方式构建的,而不是在Interface Builder中构建的。

我只是想支持所有设备方向。我的所有AutoResizing蒙版都已设置好,所有内容都会根据需要旋转和扩展/收缩。除了NavigationController的navBar和工具栏之外的所有东西。 (通常,这些视图会根据方向自动调整大小。即在横向上,导航栏和工具栏应自动调整为大约32px,并在Portrai模式下调整为44px。)特别之处在于导航控制器的子视图正在调整大小,但是实际的navBar和工具栏不是。换句话说,内容在任何方向上拉伸/缩小大约12 px,就像导航栏和工具栏调整大小一样。这似乎是自动化面具正在发挥作用。

因此,为了尝试解决这种情况,我为UINavigationController创建了一个类别,它响应'willRotateToInterfaceOrientation:duration:'以触发'sizeToFit'选择器。 (这个技术来自Stack Overflow上的另一个帖子,有类似的问题。)我发现,在我的研究中,只有最外层的视图控制器收到此消息,所以我让我的根视图控制器在选项卡控制器上调用它,反过来在导航控制器等上调用它。这解决了这个问题,现在我的嵌套视图控制器在外部视图旋转时得到通知。使用sizeToFit技术,导航栏和工具栏都会自行调整大小。但是,这仍然会留下重新定位工具栏的问题,以弥补尺寸变化的偏移。 (因为我们在iPhone中的视图坐标从左上角开始。)

在willRotate方法中使这个棘手的事情是,我们无法知道新的边界视图尺寸是什么,也不知道我们当前的方向是什么。 (除非你打开了deviceOrientationNotifications,否则我没有。)我们必须使用的是新方向,以及我们工具栏的当前帧值。我可以硬编码并使用一张草稿纸以老式的方式计算帧调整,但我真的想保留动态视图大小调整功能,而不对设备的屏幕尺寸做任何假设。

因此,使用下面的代码,我设法通过简单地将工具栏“碰撞”相对于它刚刚变成的大小12px来解决这个问题。为了防止用户翻转设备时过度碰撞,我使用当前工具栏的框架高度来导出当前方向。 (这意味着我仍在对工具栏的大小前后做出假设,但我感觉更好,因为我可以在一定程度上影响它,而不是尝试以编程方式调整设备的物理屏幕大小。)

@implementation UINavigationController (BLUINavigationControllerAutoRotate)

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    return TRUE;
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];

    // Resize the navBar
    [[self navigationBar] performSelector:@selector(sizeToFit)
                               withObject:nil
                               afterDelay:(0.5f * duration)];

    // Read our current frame size
    CGRect toolbarFrame = self.toolbar.frame;

    // Prevent over adjusting when flipping the device
    if ((toolbarFrame.size.height < 38
         && (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft
             || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight))
        || (toolbarFrame.size.height > 38
            && (toInterfaceOrientation == UIInterfaceOrientationPortrait
                || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)))
    {
        // We are already resized and repositioned.
        return;
    }

    // Calculate and apply the toolbar offset
    const NSInteger delta = 12;     // the difference in size between 44 and 32 px.
    toolbarFrame.origin.y += ((toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft)
                              || (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)) ? (delta) : (-delta);
    self.toolbar.frame = toolbarFrame;

    // Resize the toolbar
    [[self toolbar] performSelector:@selector(sizeToFit)
                         withObject:nil
                         afterDelay:(0.5f * duration)];

}

@end

所以,现在我已经正确地运行了NavigationBar和Toolbar。最终用户永远不会知道我必须实现所有这些额外的解决方法,以便重新启用看起来应该是标准行为的东西。所以我的问题是,为什么我要做所有这些?是否有一种我应该了解的更好的方法,或者我在其他地方没有做过的事情? (即[navigationController setAutomaticallyResizesToolbarOnRotate:TRUE];或类似的东西?)就像我说的,这似乎是预先连线的,所以对于我来说,必须使用转发消息和强制触发器的finagle感觉就像一个过度设计的黑客而不是正确的解决方案。

谢谢!

1 个答案:

答案 0 :(得分:3)

您正在从根视图控制器向选项卡视图控制器传递willRotateToInterfaceOrientation消息 - 为什么不传递所有其他轮换消息并查看是否有帮助?即。

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [tabBarController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [tabBarController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation  {
    [super didRotateFromInterfaceOrientation:toInterfaceOrientation];
    [tabBarController didRotateFromInterfaceOrientation:toInterfaceOrientation];
}

- (void)willAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [tabBarController willAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
}

- (void)didAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    [super didAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation];
    [tabBarController didAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation];
}

- (void)willAnimateSecondHalfOfRotationFromInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willAnimateSecondHalfOfRotationFromInterfaceOrientation:toInterfaceOrientation duration:duration];
    [tabBarController willAnimateSecondHalfOfRotationFromInterfaceOrientation:toInterfaceOrientation duration:duration];
}

我有兴趣看看如果你将所有这些传递给标签栏控制器会发生什么 - 你的问题似乎应该是自动发生的事情,而不是你所做的所有额外工作!