旋转后 UIView 坐标被交换但 UIWindow 不是?

Posted

技术标签:

【中文标题】旋转后 UIView 坐标被交换但 UIWindow 不是?【英文标题】:After rotation UIView coordinates are swapped but UIWindow's are not? 【发布时间】:2011-12-22 01:05:33 【问题描述】:

使用 Xcode 4.2.1 iPad ios 5.0.1,创建一个新的“Single View”iPad 项目。在控制器中,添加:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
    return YES;


- (void) dumpView: (UIView *) view 
    CGRect frame = view.frame ;
    CGRect bounds = view.bounds ;
    CGPoint center = view.center ;

    NSLog(@"view [%@]:%d frame=%@ bounds=%@ center=%@"
          ,   NSStringFromClass(view.class)
          ,   [view hash]
          ,   NSStringFromCGRect(frame)
          ,   NSStringFromCGRect(bounds)
          ,   NSStringFromCGPoint(center)) ;


- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation) fromInterfaceOrientation 

    NSLog(@"INViewController.didRotateFromInterfaceOrientation: %d to %d", fromInterfaceOrientation, self.interfaceOrientation) ;
    [self dumpView: self.view] ;
    [self dumpView: self.view.superview] ;

运行它,旋转设备,你会得到:

INViewController.didRotateFromInterfaceOrientation: 2 to 4
view [UIView]   bounds=0, 0, 1024, 748 center=394, 512
view [UIWindow] bounds=0, 0, 768, 1024 center=384, 512

换句话说,UIView 的坐标按预期“交换为横向”,但其父 UIWindow 仍声称处于纵向模式...

另外,UIView 的大小似乎有点不对:应该在 20 的 y 坐标在 0 ...

有人知道这是什么意思吗?

【问题讨论】:

【参考方案1】:

UIWindow 的坐标系总是纵向的。它通过设置其 rootViewController 的视图变换来应用旋转。例如,我使用单视图模板创建了一个测试应用程序并运行它。纵向:

(gdb) po [[(id)UIApp keyWindow] recursiveDescription]
<UIWindow: 0x9626a90; frame = (0 0; 768 1024); layer = <UIWindowLayer: 0x9626b80>>
   | <UIView: 0x96290e0; frame = (0 20; 768 1004); autoresize = W+H; layer = <CALayer: 0x96286a0>>

向左旋转后:

(gdb) po [[(id)UIApp keyWindow] recursiveDescription]
<UIWindow: 0x9626a90; frame = (0 0; 768 1024); layer = <UIWindowLayer: 0x9626b80>>
   | <UIView: 0x96290e0; frame = (0 0; 748 1024); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x96286a0>>

右转后:

(gdb) po [[(id)UIApp keyWindow] recursiveDescription]
<UIWindow: 0x9626a90; frame = (0 0; 768 1024); layer = <UIWindowLayer: 0x9626b80>>
   | <UIView: 0x96290e0; frame = (20 0; 748 1024); transform = [0, -1, 1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x96286a0>>

注意当设备旋转时如何设置变换(到 90 度旋转矩阵)。

关于您关于 UIView 大小的问题:视图的边界位于其自己的坐标空间中,默认情况下,视图的边界原点位于其坐标空间的原点 (0,0)。视图的框架位于其父级的坐标空间中。您可以在上面的递归描述中看到您期望的 20 个,或者直接打印框架:

(gdb) p (CGRect)[[[[(id)UIApp keyWindow] subviews] lastObject] frame]
$2 = 
  origin = 
    x = 0, 
    y = 20
  , 
  size = 
    width = 768, 
    height = 1004
  

【讨论】:

有道理。谢谢你。顺便说一句,也感谢你向我展示 gdb 可以交互使用 :-) @rob 除了 UIView.frame 的参考文档说:警告如果转换属性不是身份转换,则此属性的值未定义,因此应忽略。你能详细说明一下吗?假设我想为旋转视图的框架设置动画以将其作为叠加层滑动。 transform 不是身份时,我不会在我的代码中依赖frame。但是,frame 方法似乎总是返回 [self convertRect:self.bounds toView:self.superview],因此在调试时很有用。

以上是关于旋转后 UIView 坐标被交换但 UIWindow 不是?的主要内容,如果未能解决你的问题,请参考以下文章

UIView 图层阴影在旋转后变暗

获取旋转的矩形 UIView 角的坐标 iOS

屏幕旋转后获取自动旋转 UIView 的尺寸?

旋转 UIView 并在旋转后保持纵横比

UIView 的Transform属性以及 CGAffineTransform的使用

调整 uiview 的大小以及 uiimageview 的旋转