6

谁能给我一个详细的解释,为什么 iOS 在处理框架和转换方面的方式是横向的?

我所说的是通过在各种视图生命周期方法中记录视图描述来显示以下行为:

viewDidLoad: "UIView: 0x1edb5ba0; frame = (0 0; 568 320); autoresize = W+H; layer = <CALayer: 0x1edb5c50>"

viewWillAppear: "UIView: 0x1edb5ba0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x1edb5c50>"

viewDidAppear: "UIView: 0x1edb5ba0; frame = (0 0; 320 568); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x1edb5c50>"

这种影响是微妙的,但非常耐人寻味。

例如,我使用初始界面方向启动我的应用程序,支持的界面方向都设置为“横向(右主页按钮)”

然后我像这样显示我的 rootViewController:

self.viewController = [[MyViewController alloc] initWithNibName:nil bundle:nil];
self.window.rootViewController = self.viewController;

这个 .xib 的方向设置为横向,框架设置为 0、0、568、320。它显示正确,我可以触摸屏幕上的所有点。

当我呈现这样的子视图时,问题就来了:

SomeView *someView = [[SomeView alloc] initWithFrame:self.view.frame];
[self.view addSubview:someView];

此时,self.view.frame 报告为 (0 0; 320 568),self.view.transform 报告为 transform = [0, 1, -1, 0, 0, 0]。最好的情况,最终结果是我只能触摸我刚刚显示的视图的左侧 320px,最坏的情况是视图的布局被屠杀了。

由于各种 SO 问题,我了解到正确的方法如下:

SomeView *someView = [[SomeView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:someView]

我还没有了解到为什么,我对此非常好奇。

我更好奇的是为什么视图在实例化和显示过程中被操纵。

自从我纠结于一个仅限风景的应用程序以来已经有一段时间了,但出于某种原因,我认为当前的实现与早期版本的 iOS 不同,对吗?

4

2 回答 2

0

王子的回答很好。我只想从文档中添加关于以下frame属性的引用UIView

警告:如果该transform属性不是恒等变换,则该属性的值未定义,因此应被忽略。

另一方面,该bounds属性在视图自己的坐标系中表示,因此无论transform您设置哪个,它都不会改变。

更新:关于你的最后一段,是什么让你认为这种行为很奇怪或已经改变?iOS 可以旋转视图层次结构的唯一方法是更改​​视图转换。因此,如果您希望不同视图控制器中的所有视图都以相同的方式定向,您应该使用某种导航视图控制器,或者以模态方式呈现您的控制器。这样,每个控制器将根据相同的规则旋转其视图,您不必手动管理视图间转换。

在早期,您可以看到如下代码:

UIViewController *ctrl = ...;
[window addSubview.ctrl.view];

这是以前windowrootViewController属性,人们倾向于滥用它来获取自己的观点,这会在设备旋转时产生令人惊讶的结果。如果您说您再也看不到此代码,那肯定是一种变化,而且是一种更好的变化,因为该代码被破坏了。所以人们只是学会了编写在方向改变的情况下能正常工作的代码。

如果您的游戏的所有 UI 都由游戏引擎渲染,那么您只需要一个(根)视图控制器。在这种情况下,您根本不需要担心转换。只需查询边界glView并相应地调整您glViewport和游戏中的元素。由于glView不同设备的边界不同,只要您不对实际屏幕尺寸和视图的当前方向做出任何假设,您的游戏就会在所有设备上优雅地缩放。

于 2013-05-15T10:15:38.640 回答
0

根据苹果的说法,默认情况下,应用程序同时支持纵向和横向。当基于 iOS 的设备的方向发生变化时,系统会发出 UIDeviceOrientationDidChangeNotification 通知,让任何相关方知道发生了变化。默认情况下,UIKit 框架会监听这个通知并使用它来自动更新你的界面方向。这意味着,除了少数例外,您根本不需要处理此通知。

您必须给出边界而不是框架的原因很简单。一旦应用程序处于横向状态,与纵向视图相比,它的宽度和高度就会互换。所以这会导致损坏的行为。但是在给出边界时,它会考虑视图的方向并相应地采用高度和宽度。

当您的视图控制器非常靠近视图层次结构的顶部(或实际上位于顶部)时,您会发现您获得了宽度和高度的这种“交换”效果。交换通常表现在框架上,而不是视图的边界上。这是因为边界实际上是应用于框架的一些变换——有时这些变换包括 90 度旋转(由于设备处于横向模式)。请注意,检查 frame 属性的确切时间也很重要。如果您在视图加载之后但在它出现在屏幕上之前检查属性,您可能会得到“错误”的结果。

于 2013-05-15T08:19:02.847 回答