iPad/iPhone多方向最佳实践?

4
我希望将我的视图转换为适用于任何方向(特别是在iPad上推荐使用)。我一直在使用IB来布局,但不确定最佳方式。理想情况下,我希望在IB中旋转视图,重新布局,并将两个方向保存到同一个XIB中,以便视图在方向更改时自动知道该做什么。但这似乎是不可能的。
我知道当方向更改时可以在代码中重新排列视图,但这样做没有使用IB的太多意义,因为它对我来说主要优势之一是将所有丑陋的布局代码与我的逻辑分离开来。
其他人是如何处理这个问题的?他们只是设计自己的视图,使UIViewAutoResizing标志可以适当地处理旋转吗?他们是否为每个方向都有多个视图,并且以某种方式平稳地切换这些视图?

可能是iphone/ipad方向处理的重复问题。 - Eimantas
就我个人而言,我建议简单地继承UIView并实现-layoutSubviews方法,通过比较bounds.size.width和bounds.size.height来区分“纵向”和“横向”(如果您决定将其嵌入到另一个视图中,这也使其更具可重用性)。我认为我无法忍受管理16个nib文件(iPhone和iPad的8种语言),特别是当您必须针对特定语言进行布局调整时... - tc.
是的,这似乎是最好的方法。但很遗憾,因为我喜欢将所有视图内容都放在nib文件中,并且可以在IB中轻松更改。哦,算了。 - initlaunch
3个回答

5
我在这里(以及StackOverFlow上关于此主题的其他地方)找到了信息,这让我开始思考我的先前答案。如果您有很多顶级对象,这只会变得乏味。
然后,我想到可以创建一个“辅助”对象,因此我创建了一个项目来演示该技术。基本上,助手在视图中具有每个感兴趣对象的出口。ViewController本身有两个Helper对象(一个用于p,一个用于l),并且您在NIB中实例化它们。在方向更改时,将视图控制器的helper指针切换到适当的helper,然后更新self.view。它真的很简单(这个文本更难)。
那么,你会如何开始?好吧,如果您预先知道需要两个单独的视图,那么这有所帮助。一旦知道了这一点,请参考下面引用的项目中的Helper模板,进行调整,将其添加到NIB中,然后将帮助连接到肖像视图中的适当对象上。视图控制器本身只有对两个助手的引用和“curHelper”指针。 Helper ivars是公共的,因此视图控制器可以引用诸如“curHelper->label1.text = ...”之类的项目 - 成本是单个指针解除引用(也可以使用属性 - 您的呼叫)。
此外,您还可以直接连接来自任一视图中的对象的IBActions。因此,让我们逐步进行:
- 创建NIB - 创建Helper对象,并在nib中实例化一个称为Portrait的对象 - 将所有IBOutlets添加到Helper对象中,在dealloc和viewWillUnload中处理它们 - 在ViewController中正常放置IBActions - 将NIB连接起来 - Helper-> Portrait视图输出,操作传递给ViewController - 在肖像中使其全部运作 - 添加新的Helper对象,将其称为Landscape - 复制当前肖像视图,旋转它并保存它 - 将景观助手的输出线路连接到新的景观视图(操作已经为您设置!)
显然,从现在开始,您需要进行重复更改,但是在任何双重nib方案中,您都必须这样做。在上述技术中,所有出口名称保持不变。
当ViewController收到“viewDidUnload”时,需要将其发送到两个帮助程序,并使Helpers解除分配(然后解除分配其输出)。
注意:我只是把它放在一起看看它的样子。如果您想查看代码和一个非常小的演示,请从public dot me dot com slash dhoerl下载它,在iPhone文件夹中命名为Helpers.zip。如果需要,我会更新此内容和此文本。

这是一个相当不错的解决2个引用问题的方法。我仍然对双nib方法感到不满,因为您必须在内存中拥有每个子视图的两个副本(或在方向更改时重新创建它们),而且您无法对子视图进行动画处理。到目前为止,我只是设计我的布局,以便自动调整大小可以处理旋转-这样会更加限制,但工作/杂乱少一些。 - initlaunch
1
好方法。 (我不需要15个或更多字符来说“好方法”。) - Mustafa
1
请问您能再次将这个Helpers.zip文件放到您的iDisk上吗?听起来非常有用! - TheLearner

5
你可以在同一个XIB中创建两个独立的视图,然后实现以下代码:
对于@interface
IBOutlet UIView *landscapeView;
IBOutlet UIView *portraitView;

并且到 @implementation

- (void) viewDidLoad {
self.view.frame = [[UIScreen mainScreen] applicationFrame];
  landscapeView.autoresizesSubviews = NO;  <- IMPORTANT!
  portraitView.autoresizesSubviews = NO;   <- IMPORTANT!
}
- (BOOL)shouldAutorotateToInt .... {
  if ((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation == UIInterfaceOrientationLandscapeRight) self.view = landscapeView;
  else if ((interfaceOrientation == UIInterfaceOrientationPortrait) || (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) self.view = portraitView;
  return YES;
}

这意味着我需要拥有每个子视图的两份副本,一个属于纵向视图,一个属于横向视图,对吗?如果我的控制器想要引用其中一个子视图,那么它就需要有两个引用了? - initlaunch
你需要为所有子视图都准备2个插座吗? - TheLearner
在这种方法中,我们是否可以维护控件的状态?例如,我的应用程序中有一个文本字段,用户已经在文本字段中输入了一些文本,然后更改了方向。那么他需要再次输入文本吗? - ios

0

看上面的代码,使用两个视图 - 我喜欢。为了回应“现在我必须维护两个引用”的评论,有一个解决方法 - 使用“references”(我的术语)。

给视图和插座命名前缀为l和p,然后使用您现在使用的基本名称定义“伪”ivars。当您首次viewDidLoad(或其他地方)时,将所有“伪”ivars设置为l或p变体。当您切换方向时,只需将伪变量设置为另一方向(以及其他操作)。

在viewDidUnload和dealloc中,仅引用l和p项 - “真正的”IBOutlets - 并简单地将伪ivars置为空。使它更丑陋 - 在真正的IBOutlets前面加上l_no_no_no_或其他内容,以免不小心使用其中一个。

如果将伪ivars属性化,请使用ASSIGN而不是RETAIN !!!


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