15

现在设计多方向iPad应用程序的正确方法是什么?我已经阅读了很多 Apple 文档、网络资源和一些 SO Q&A。这是我的初步要求:

  • 这必须适用于 iOS 5 及更高版本。无需创建与 iOS 早期版本的向后兼容性。
  • 如果可能的话,我希望在不同的 NIB 文件中定义纵向和横向 UI。
  • header.png对于不同方向的相同 UI 元素,我的 NIB 文件将具有不同的图像(例如,我将拥有header-landscape.pngUIImageView。
  • 应用程序将有几个屏幕,我需要能够在每个屏幕上切换方向。

那我该怎么办?

  • 每个屏幕创建一个 VC 并替换willRotate处理程序中的底层视图?
  • 每个方向创建一个 VC?但是,您如何正确切换它们呢?
  • 简单地重新排列元素是行不通的(我认为),因为我必须重新加载图像。
  • 用代码写所有东西(我真的很讨厌这个想法)?

到目前为止,解决这个问题的正确方法是什么?

4

5 回答 5

18

我实际上认为这是一个非常复杂的主题,就像大多数架构问题一样。我不认为您应该尝试仅使用一种技术来解决问题。

为了不排挤此页面上的所有其他答案,我在我的博客上发布了一篇完整的文章一些示例代码的链接,也是

概括

最好在 .xib 文件中表达您的 UI,尽管您允许自己偏离这一点的程度部分取决于将来修改您的应用程序的人员的技能组合。可能不仅仅是程序员

首选选项

强烈建议使用一个 .xib 文件和一个子类来实现一个逻辑UIViewController视图。努力做到这一点。设置autoresizesSubviews=YES您的 XIB 的 root view,并适当地调整子视图autoresizingMask以适应屏幕尺寸/方向的变化可以有很长的路要走。

但是,这并不总是足够的。 如果您的布局需要横向调整,超出自动调整大小可以处理的范围,我使用两个主要选项。您应该选择哪一个取决于您的视图内容。

选项一

如果纵向与横向的布局差别不大,那么我建议保留一个 .xib,并在视图控制器中添加一些代码来调整旋转布局。

选项二

如果横向与纵向的差异非常显着,那么我建议为每个方向使用一个 .xib(具有严格的命名约定,例如MyViewController.xiband MyViewController-landscape.xib)。但是,两个 .xib 文件都应该将File's Owner连接到同一个 View Controller类!对我来说,这是关键。

如果您打算做任何事情,而不是首选替代方案,我建议创建一个可重用的UIViewController基类来自动执行此操作并保持一致。这比你一开始想象的要多,而且在每个UIViewController需要轮换处理的子类中继续这样做是很愚蠢的。


解决方案

我创建了这样一个基类,并将其放在此处的示例项目中。 您可以看到一个 Hello World 示例,说明我认为应该如何处理所有三种情况:

  • 一个视图控制器和一个 .xib,仅自动调整大小(我的FirstViewController
  • 一个视图控制器和两个 .xib,在它们之间自动切换(我的SecondViewController
  • 一个视图控制器和一个 .xib,具有较小的旋转编程布局 ( ThirdViewController)

我使用的RotatingViewController基类同样适用于 iPhone 应用程序。实际上,我有一个更复杂的版本来处理维护 iPadiPhone、纵向横向布局(用于通用应用程序)。

但是,这个问题只是关于 iPad 的,所以我把它删掉了,以便更容易理解。

我的基类还有一个实用imageNamed:方法,可以帮助加载适合当前方向的图像(以image-landscape.png约定命名)。但是,我认为绝大多数时候应该使用可拉伸的 UIImages 。

我没有这样做,但是当设备方向改变时,RotatingViewController它也可以尝试遍历它的subviews树并更新对象的属性image。我没有做到这一点,但你可以。UIButtonUIImageView

这些建议的更多理由可在我参考的博客文章中找到

于 2012-07-27T09:08:34.327 回答
4

因此,由于缺乏对这个问题的答案并且时间是一个问题,我最终做了以下事情:

  • 使用 Interface Builder 为所有纵向屏幕创建 NIB 文件。将所有需要布局的控件绑定到插座。
  • 使用 IB 也可以为横向创建 NIB 文件,但仅将其用作参考,以查看 UI 元素的框架在横向中的位置。
  • willAutoRotate添加了代码以在处理程序中将所有元素重新排列为横向并返回纵向。

这种方法让我可以灵活地在 IB 中创建大部分 UI。我仍然需要保留代码以将元素重新排列到不同的方向,但通常这只涉及setFrame标签、按钮等和imageNamed图像的方法。与直接在代码中创建所有 UI 相比,范围要小得多。

只要允许,我就会在这个问题上展开悬赏,因为我认为这个问题对于任何为 iPad/iPhone 创建通用和多方向应用程序的开发人员来说都非常重要和有用。

于 2012-07-25T00:42:58.037 回答
2

我使用了 3 种不同的技术,其中一种我认为是处理多个方向的“正确”方法。

  1. 不正确:创建了两个不同的 nib/xib。不是“坏的”,但是当你在 UIViewController 中不断地重构 UIView 时,处理上下文和状态是很痛苦的。
  2. 不正确:使用一个笔尖并根据绝对坐标在旋转时重新定位它们。这是错误的做法。我一遍又一遍地看到这一点,但这是您可以完成处理多种查看模式的最糟糕的方式。这种情况的一个症状是具有设备方向意识的 UIView。完全没有必要。
  3. 正确:使用视图内的元素的autoresizingMask将它们浮动到设备旋转的正确位置,调整使用 CGRect 框架无法以这种方式完成的操作。我只需要这样做一次就可以对齐某些东西。恕我直言,这是处理多个设备方向的“正确”方式。UIView 和任何子视图不需要知道旋转。您可以在每个屏幕上使用一个带有许多子视图的 VC,并保持简单。如果您的布局可以以这种方式设计,带有浮动元素,那么您就是金子,UI 是轻而易举的事。

只是我的两分钱。

编辑:iOS 6 引入了 AutoLayout,可以用来代替“支柱和弹簧” - https://developer.apple.com/library/ios/documentation/userexperience/conceptual/AutolayoutPG/Introduction/Introduction.html

于 2012-07-26T17:07:38.570 回答
0

令我失望的是,Apple 没有为给定的视图控制器提供使用多个 XIB 文件(每个方向一个)的方法——这将是处理方向问题的一种很好的方法,因为自动调整很少能很好地处理方向(它只适用于非常简单的界面)。

您可以这样做:为纵向创建一个 XIB,并为 XIB 中的每个子视图分配一个唯一的标签属性。然后复制 XIB,重新做横向布局(所以现在你有两个 XIB,一个纵向和一个横向)。

当您的应用程序启动时,您首先从适合启动方向的任何 XIB 创建视图控制器。递归遍历所有子视图,并创建一个包含所有子视图帧的字典,由每个子视图的 tag 属性键控。

接下来,从另一个方向的 XIB 创建一个临时视图控制器,并执行相同的递归迭代,将标签键控的所有帧存储到第二个字典(每个字典匹配一个方向,并应相应命名)。然后处理第二个临时视图控制器。

layoutSubviews(实际上是在 中viewDidLayoutSubviews,因为您正在处理视图控制器并且您可以执行 iOS 5+),您所要做的就是递归地遍历所有子视图,并为每个子视图分配适合的框架字典中的框架当前方向,基于子视图的标签属性。

这种技术将允许您保留视图控制器的状态,而无需在每次方向更改时重新加载它。它还允许您使用 IB 布局视图控制器,因此您不必编写一堆手动布局代码。

于 2012-07-31T21:48:32.633 回答
-3

为什么要在一个可以做所有事情的应用程序之后运行?当你设计一个应用程序时,你决定什么是它的最佳方向 - 横向或纵向 - 即使你的应用程序的设计需要反向(所有都是横向的,1-2 个控制器是纵向的,反之亦然),你将相应地制作笔尖。好吧,在某些情况下,您将需要一个控制器来支持所有方向,并且您会做到的。

但是试图让所有控制器都支持所有方向......好吧,我觉得这个想法有点奇怪。

以防万一您仍然想这样做,您已经列出了可能的解决方案,我喜欢最后一个选项。

于 2012-07-23T23:29:53.043 回答