【问题标题】:Orientation in a UIView added to a UIWindow添加到 UIWindow 的 UIView 中的方向
【发布时间】:2024-01-16 10:21:01
【问题描述】:

我有一个 UIView,它应该覆盖整个设备 (UIWindow) 以支持图像放大/缩小效果,我正在使用核心动画,其中用户点击 UITableViewCell 上的按钮并缩放关联的图像。

缩放性能完美,我无法弄清楚为什么即使设备处于横向状态,子视图仍处于纵向模式。下图:

我确实有一个导航控制器,但这个视图已直接添加到 UIWindow。

【问题讨论】:

标签: iphone uiview orientation uiwindow


【解决方案1】:

您可以在此处了解一些可能的原因:
Technical Q&A QA1688 - Why won't my UIViewController rotate with the device?

在您的情况下,您可能将视图作为另一个子视图添加到窗口中。只有第一个子视图获取旋转事件。您可以做的是将它添加为第一个窗口子视图的子视图。

UIWindow* window = [UIApplication sharedApplication].keyWindow;
if (!window) 
    window = [[UIApplication sharedApplication].windows objectAtIndex:0];
[[[window subviews] objectAtIndex:0] addSubview:myView];    

【讨论】:

  • 太棒了 - 感谢您提供 QA 链接。在官方文档中,它没有记录(我已经搜索了 View 和 Window 编程指南,以及 UIWindow 和 UIView 类,找不到任何提及它),并且显然是一个巨大的错误(Apple 无意修复,判断根据 QA 文章的语气)。
  • 如果您想在模态视图控制器(至少从 iOS5 开始)前面显示,则添加到第一个子视图将不起作用,因为模态视图控制器被添加为主视图上的第二个视图层次结构UIWindow 子视图。
  • @FábioOliveira :- +1,感谢您强调其中的缺点,我也会记住这一点。 :)
  • 但如果我们的应用程序有 UINavigationController,它会在 myView 顶部显示 NavigationBar。为什么会这样?
  • 当 [window subviews] 时你可能会得到 count = 0
【解决方案2】:

问题

从 iOS 6 开始,只有最顶层的视图控制器(与 UIApplication 对象)参与决定是否轮播 响应设备方向的变化。

https://developer.apple.com/library/content/qa/qa1688/_index.html

解决办法

我已经开源了一个名为 AGWindowView 的 pod。
它会自动处理任何旋转和帧变化,因此您不必担心。

代码

它支持 SDK 和 iOS 系统版本的任意组合。相关代码可以在这里找到: https://github.com/hfossli/AGWindowView/blob/master/Source/AGWindowView.m

【讨论】:

  • 这是一个非常棒的库!谢谢!
  • 对于我正在处理的项目非常有用的代码,该项目需要在当前显示的内容之上呈现视图。杰出的。谢谢!
  • 你是救生员。希望我能在几个小时前找到这个!
  • 视图似乎会调整大小以填充旋转窗口。你如何保持原来的大小?
  • 感谢 hfossli 和 ThomasW。继续努力吧。 +1
【解决方案3】:

我在 UIApplication 上创建了一个类别,它有一个帮助属性和获取 keyWindow 的第一个子视图的方法。无论如何,这是您要覆盖的视图。现在,当您将由 UIViewController 管理的视图添加到该视图时,将调用 shouldRotateToInterfaceOrientation: 方法。

UIApplication+WindowOverlay.h

#import <UIKit/UIKit.h>

@interface UIApplication(WindowOverlay)

    @property (nonatomic, readonly) UIView *baseWindowView;

    -(void)addWindowOverlay:(UIView *)view;

@end

UIApplication+WindowOverlay.m

#import "UIApplication+WindowOverlay.h"

@implementation UIApplication(WindowOverlay)

    -(UIView *)baseWindowView{
        if (self.keyWindow.subviews.count > 0){
            return [self.keyWindow.subviews objectAtIndex:0];
        }
        return nil;
    }

    -(void)addWindowOverlay:(UIView *)view{
        [self.baseWindowView addSubview:view];
    }
@end

这就是你将如何使用它。

//at the top of the file...or in {yourproject}.pch
#import "UIApplication+WindowOverlay.h

//in a method:

UIView *view = [UIView new];

UIView *window = [UIApplication sharedApplication].baseWindowView;

view.frame = window.bounds;

[window addSubview:view];

//or

[[UIApplication sharedApplication] addWindowOverlay:view];

【讨论】:

  • 获取方向改变事件怎么样?
  • 您的视图将被旋转,并且如果您使用它,自动调整大小的蒙版将得到尊重。它基于上面应该接受的答案。我没有具体获取轮换事件的答案,但我确信它已在其他地方得到解答。
  • 好的。我错过了窗口第一个子视图的子视图部分。那么这种方法的一个问题是您不能从模态视图控制器中呈现它。也许如果你将它添加为最后一个窗口的子视图的子视图。这样,如果您有一个模态视图控制器,显示主窗口上有两个子视图:根视图控制器视图和模态视图控制器的调光视图,并且您想将其添加到调光视图中,因此它显示在顶部。
  • 如果你有一个 UIAlertView ,这将不会在 iOS 7 上工作,因为这将是关键窗口。 [[UIApplication sharedApplication] windows][0] 将始终返回应用程序的窗口。
【解决方案4】:

这是因为正如您提到的,您的视图已直接添加到 UIWindow,因此当为导航控制器调用旋转方法时,uiview 没有任何反应。如果 UIView 是视图控制器视图的子视图,它会旋转。如果由于某种原因无法做到这一点。然后你可以重写这个方法:

// This method is called every time the device changes orientation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
}

而且每次你​​的方向改变也会改变你的视图方向。

【讨论】:

    【解决方案5】:

    我在将视图直接添加到窗口时遇到了类似的问题。也许这会有所帮助:Automatically Sizing UIView after Adding to Window

    【讨论】:

      【解决方案6】:

      我如何解决这个问题的另一种解决方案。

      定义当前方向:

      @interface AJImageCollectionViewController (){
          UIInterfaceOrientation _currentOrientation;
      }
      @end
      

      然后在viewWillLayoutSubviews中检查方向:

      - (void)viewWillLayoutSubviews {
          [self checkIfOrientationChanged];
      }
      
      - (void)checkIfOrientationChanged {
          UIInterfaceOrientation newOrientation = [[UIApplication sharedApplication] statusBarOrientation];
          BOOL newOrientationIsPortrait = UIInterfaceOrientationIsPortrait(newOrientation);
          BOOL oldOrientationIsPortrait = UIInterfaceOrientationIsPortrait(_currentOrientation);
      
          // Check if the orientation is the same as the current
          if(newOrientationIsPortrait != oldOrientationIsPortrait){
              _currentOrientation = newOrientation;
              // Do some stuff with the new orientation
          }
      }
      

      【讨论】:

        最近更新 更多