在 iOS 8 中处理方向变化的“正确”方法是啥?

Posted

技术标签:

【中文标题】在 iOS 8 中处理方向变化的“正确”方法是啥?【英文标题】:What is the "right" way to handle orientation changes in iOS 8?在 iOS 8 中处理方向变化的“正确”方法是什么? 【发布时间】:2014-09-26 23:53:37 【问题描述】:

谁能告诉我在 ios 8 中使用纵向和横向界面方向的“正确”或“最佳”方法?似乎我想为此目的使用的所有功能在 iOS 8 中都已弃用,而且我的研究没有找到明确、优雅的替代方案。我真的应该查看宽度和高度来自己确定我们是处于纵向还是横向模式吗?

例如,在我的视图控制器中,我应该如何实现以下伪代码?

if we are rotating from portrait to landscape then
  do portrait things
else if we are rotating from landscape to portrait then
  do landscape things

【问题讨论】:

阅读 UIViewController 的文档。请参阅标题为“处理视图旋转”的部分。它解释了您应该做什么。 它们已被弃用是一个线索。您必须使用其他东西....其他东西应该是 AutoLayout 和 Size Classes :-) 【参考方案1】:

Apple 建议使用尺寸等级作为可用屏幕空间的粗略衡量标准,以便您的 UI 可以显着改变其布局和外观。考虑纵向的 iPad 与横向的 iPad 具有相同的尺寸等级(常规宽度、常规高度)。这意味着您的 UI 在两个方向之间应该或多或少相似。

但是,iPad 中从纵向到横向的变化非常显着,您可能需要对 UI 进行一些较小的调整,即使尺寸等级没有改变。由于UIViewController 上的界面方向相关方法已被弃用,Apple 现在建议在UIViewController 中实现以下新方法作为替代:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator

    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    // Code here will execute before the rotation begins.
    // Equivalent to placing it in the deprecated method -[willRotateToInterfaceOrientation:duration:]

    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) 

        // Place code here to perform animations during the rotation.
        // You can pass nil or leave this block empty if not necessary.

     completion:^(id<UIViewControllerTransitionCoordinatorContext> context) 

        // Code here will execute after the rotation has finished.
        // Equivalent to placing it in the deprecated method -[didRotateFromInterfaceOrientation:]

    ];

太棒了!现在,您在轮换开始之前和结束之后都会收到回调。但是实际上知道旋转是纵向还是横向呢?

Apple 建议将旋转视为父视图大小的简单变化。换句话说,在 iPad 从纵向旋转到横向期间,您可以将其视为根级视图,只需将其 bounds.size768, 1024 更改为 1024, 768。知道这一点后,您应该使用上面传递给viewWillTransitionToSize:withTransitionCoordinator: 方法的size 来确定您是旋转到纵向还是横向。

如果您想要一种更无缝的方式将遗留代码迁移到新的 iOS 8 处事方式,请考虑在 UIView 上使用this simple category,它可用于确定视图是“纵向”还是“横向”根据它的大小。

回顾一下:

    您应该使用尺寸等级来确定何时显示根本不同的 UI(例如,“类似 iPhone”的 UI 与“类似 iPad”的 UI) 如果您需要在尺寸类别发生变化但容器(父视图)尺寸发生变化时(例如 iPad 旋转时)对 UI 进行较小的调整,请使用 viewWillTransitionToSize:withTransitionCoordinator: 回调在 UIViewController 中。 应用中的每个视图都应仅根据为其布局的空间做出布局决策。让视图的自然层次结构将这些信息向下级联。 同样,不要使用statusBarOrientation(基本上是设备级属性)来确定是否为“纵向”和“横向”布局视图。状态栏方向只能由处理诸如 UIWindow 之类的代码使用,这些代码实际上位于应用的最根级别。

【讨论】:

优秀的答案!顺便说一句,你在 AL 上的 youtube 视频内容丰富。感谢分享。看看这个! youtube.com/watch?v=taWaW2GzfCI 我发现的唯一问题是有时您想知道设备方向,而这不会让您知道。在 iPad 上,它在状态栏或设备方向值更改之前被调用。您无法判断用户是纵向持有设备还是纵向倒置。也无法测试,因为嘲笑 UIViewControllerTransitionCoordinator 是一场噩梦 :-( @Darrarski 你有没有找到一个优雅的解决方案来解决这些问题? 那么viewdidlayoutsubviews 在哪里?我认为viewdidlayoutsubviews 用于捕获由于旋转引起的绑定变化。你能详细说明一下吗? 如果我们不使用状态栏方向,如何区分横向左侧和横向右侧?我需要这种区别。此外,这里描述的还有其他问题 - ***.com/questions/53364498/…【参考方案2】:

基于smileyborg 非常详细(并被接受)的答案,这里是使用swift 3 的改编:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) 
    super.viewWillTransition(to: size, with: coordinator)
    coordinator.animate(alongsideTransition: nil, completion: 
        _ in
        self.collectionView.collectionViewLayout.invalidateLayout()
    )        

UICollectionViewDelegateFlowLayout 实现中,

public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
    // retrieve the updated bounds
    let itemWidth = collectionView.bounds.width
    let itemHeight = collectionView.bounds.height
    // do whatever you need to do to adapt to the new size

【讨论】:

【参考方案3】:

我只是使用通知中心:

添加一个方向变量(将在最后解释)

//Above viewdidload
var orientations:UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation

视图出现时添加通知

override func viewDidAppear(animated: Bool) 
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationChanged:", name: UIDeviceOrientationDidChangeNotification, object: nil)

视图消失时删除通知

override func viewWillDisappear(animated: Bool) 
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIDeviceOrientationDidChangeNotification, object: nil) 

触发通知时获取当前方向

func orientationChanged (notification: NSNotification) 
    adjustViewsForOrientation(UIApplication.sharedApplication().statusBarOrientation)

检查方向(纵向/横向)并处理事件

func adjustViewsForOrientation(orientation: UIInterfaceOrientation) 
    if (orientation == UIInterfaceOrientation.Portrait || orientation == UIInterfaceOrientation.PortraitUpsideDown)
    
        if(orientation != orientations) 
            println("Portrait")
            //Do Rotation stuff here
            orientations = orientation
        
    
    else if (orientation == UIInterfaceOrientation.LandscapeLeft || orientation == UIInterfaceOrientation.LandscapeRight)
    
       if(orientation != orientations) 
            println("Landscape")
            //Do Rotation stuff here
            orientations = orientation
        
    

我添加方向变量的原因是,在物理设备上进行测试时,方向通知会在设备中的每一个微小移动时被调用,而不仅仅是在它旋转时。添加 var 和 if 语句仅在代码切换到相反方向时调用。

【讨论】:

这不是 Apple 推荐的方法,因为这意味着您应用中的每个视图都根据设备的方向来决定如何显示,而不是考虑给定的空间。 Apple 也没有在 8.0 中考虑硬件。告诉 AVPreview 层,如果它呈现在视图控制器上,它不需要担心方向。不起作用,但它已在 8.2 中修复 super of viewDidAppearviewWillDisappear 应该被调用 注意:UIDeviceOrientation != UIInterfaceOrientation。在我的实验中,statusBarOrientation 是不可靠的。【参考方案4】:

从 UI 的角度来看,我认为 Apple 推荐使用 Size Classes 来处理不同方向、大小和比例的界面。

请参阅以下部分:特征描述接口的大小类和规模: https://developer.apple.com/library/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS8.html

“iOS 8 增加了新功能,使处理屏幕尺寸和方向更加通用。”

这篇文章也是一篇好文章: https://carpeaqua.com/thinking-in-terms-of-ios-8-size-classes/

编辑 更新链接: https://carpeaqua.com/2014/06/14/thinking-in-terms-of-ios-8-size-classes/(图片来源:Koen)

【讨论】:

是的,看起来他的整个网站现在都关闭了。 这篇文章确实值得一读,这里是正确的地址:carpeaqua.com/thinking-in-terms-of-ios-8-size-classes 但是,如果我们不是在谈论尺寸等级和 UI,而是在谈论 AVFoundation,例如。录制视频时,在某些情况下,您必须知道 viewControllers 的方向才能设置正确的元数据。这简直是​​不可能的。 “多才多艺”。 这不是 OP 所要求/谈论的内容。 更新链接:carpeaqua.com/2014/06/14/…

以上是关于在 iOS 8 中处理方向变化的“正确”方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

通过方向更改获取屏幕宽度/高度的正确方法是啥?

iPad - 通过重新加载的 loadView 处理方向变化

iOS 8 方向变化检测

处理鼠标拖动的正确方法是啥?

如何在iOS中设置方向变化的webview框架?

iOS 8 中呈现的视图控制器中的界面方向不正确