【问题标题】:How to properly design multi-orientation iPad application如何正确设计多方向 iPad 应用程序
【发布时间】:2012-07-23 23:00:30
【问题描述】:

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

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

那我该怎么办?

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

截至今天,解决此问题的正确方法是什么?

【问题讨论】:

  • 您可以使用嵌套的视图控制器来解决“每个方向一个 VC”的问题。
  • 您已经描述了一种可能的解决方案是“每个方向一个 VC”,并且您还提到了正确切换它们时可能出现的问题。好吧,简单的解决方案是使用自 iOS5 以来可用的嵌套 viewController - speakerdeck.com/u/peterfriese/p/…
  • 所以基本上创建一个控制器容器并将所有视图控制器(每个屏幕每个方向一个)并在容器内的这些控制器之间切换?

标签: iphone objective-c ipad interface-builder orientation


【解决方案1】:

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

为了不挤占此页面上的所有其他答案,I posted a full-writeup on my blog 和 a link to some sample code, too

总结

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

首选选项

最好使用一个.xib 文件和一个UIViewController 子类来实现一个逻辑视图。努力做到这一点。在 XIB 的根 view 上设置 autoresizesSubviews=YES,并适当地调整子视图的 autoresizingMask 以适应屏幕大小/方向的变化可以大有帮助。

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

选项一

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

选项二

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

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


解决方案

我创建了这样一个基类,put it in a sample project here. 你可以看一个 Hello World 示例,说明我认为应该如何处理所有三个场景:

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

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

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

My base class 还有一个实用程序imageNamed: 方法,可以帮助加载适合当前方向的图像(以 image-landscape.png 约定命名)。但是,我认为stretchable UIImages should be used 大部分时间都是如此。

我没有这样做,但是当设备方向发生变化时,RotatingViewController 也可以尝试遍历其subviews 树并更新UIButton 或UIImageView 对象上的image 属性。我没有做到这一点,但你可以。

有关这些建议的更多理由,请访问on the blog post I reference

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

      【解决方案3】:

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

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

      只有我的两分钱。

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

      【讨论】:

      • 谢谢。确实有道理,但是如何在(3)中将不同的图像加载到 UIImageViews 中?
      • 啊,我在那里所做的实际上是通过使用 NSNotificationCenter 类附加到方向更改事件然后调用重新定位或加载另一个图像的函数来使用方向感知的 UIView,例如this blog post。当您希望将视图与 UIViewController 分开时,这是一个很好的方法。 如果您想要更简单但紧密耦合的东西,您可以在设备方向更改时在 UIViewController 中重新加载图像并重新加载视图/子视图。
      【解决方案4】:

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

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

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

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

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

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

      【讨论】:

        【解决方案5】:

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

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

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

        【讨论】:

        • 我有点不同意你的第一点。完全。至于支持控制器中的所有方向 - 控制器不应该关心方向,只要所有元素都存在于两者中。我只是想知道切换它的最佳方式。
        • 提供多个方向的想法绝对一点也不奇怪。这完全取决于用户所处的“模式”。如果应用支持多种“模式”,那么它也应该支持多个方向。我所说的“模式”是指“娱乐”与“需要的信息”之类的场景——如果你不是来自概念方面,这可能仍然有点难以理解......
        • @TeodorCarseta (-1) 原因很简单。 Apple 文档指定 iPad 应用程序应该能够或在任何方向上工作。 (他们确实允许对于某些游戏风格的应用程序,这可能是不可能的)。
        • 奇怪与否,客户想要它。如果应用程序不支持它,他们会立即注意到。一些 Apple 的应用程序不支持多模式,但是,它们是 Apple,它们可以做到这一点。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-24
        • 1970-01-01
        • 1970-01-01
        • 2011-06-05
        • 2013-03-16
        • 1970-01-01
        相关资源
        最近更新 更多