UINavigationController 工具栏和设备方向(旋转)
Posted
技术标签:
【中文标题】UINavigationController 工具栏和设备方向(旋转)【英文标题】:UINavigationController Toolbar and device orientation (rotation) 【发布时间】:2010-10-03 02:04:52 【问题描述】:所以我有这样一个嵌套设置的 iPhone 应用程序: [RootViewController]->[UITabBarController]->[UINavigationController]->[subViewControllers]。一切都是以编程方式构建的,而不是在 Interface Builder 中。
我只是想支持所有设备方向。我所有的 AutoResizing 蒙版都已设置好,一切都在必要时旋转和扩展/收缩。除了 NavigationController 的 navBar 和 Toolbar 之外的所有内容。 (通常,这些视图会根据方向自动调整大小。即在横向中,导航栏和工具栏应自动调整为大约 32 像素,在纵向模式下应自动调整为 44 像素。)奇怪的是导航控制器的子视图正在调整大小,但是实际的导航栏和工具栏不是。换句话说,内容在任何方向上都会拉伸/收缩大约 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]; 或类似的东西?)就像我说的,这似乎应该是预先连接的,所以我不得不处理转发消息和强制触发器感觉就像一个过度设计的黑客而不是正确的解决方案。
谢谢!
【问题讨论】:
【参考方案1】:您正在将 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];
我很想看看如果您将所有这些都传递给标签栏控制器会发生什么 - 您的问题似乎应该自动发生,而不是您完成的所有额外工作!
【讨论】:
是的!这样可行。实际上,只需要添加 'willAnimateRotationToInterfaceOrientation:' 即可使其工作。我已经有了 willRotate 和 didRotate。但是,如果您使用“willAnimateRotationToInterfaceOrientation:”,则不应使用“willAnimateFirstHalfOfRotationToInterfaceOrientation:”或“willAnimateSecondHalfOfRotationToInterfaceOrientation”。 'didAnimate...' 方法也是如此。无论如何,长话短说,(字面意思)就是这样。谢谢! :)以上是关于UINavigationController 工具栏和设备方向(旋转)的主要内容,如果未能解决你的问题,请参考以下文章
UINavigationController 推送视图和显示工具栏有奇怪的工具栏动画
UINavigationController 底部工具栏在 hideBarsOnTap 之后不保留其状态
设置 UINavigationController 的工具栏项
如何检测 UINavigationController 工具栏背景上的触摸