在iOS 8中处理方向更改的“正确”方法是什么?


104

有人可以告诉我在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

3
阅读有关的文档UIViewController。参见“处理查看Rotations`部分它说明了你应该做的。
rmaddy

他们已被弃用是一个线索。您必须使用其他东西。...其他东西应该是AutoLayout和Size Classs :-)
Aaron

Answers:


262

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.size从更改为{768, 1024}即可{1024, 768}。然后知道了这一点,您应该使用上面sizeviewWillTransitionToSize:withTransitionCoordinator:方法传递的内容来确定要旋转到纵向还是横向。

如果您想以更无缝的方式将旧代码迁移到新的iOS 8处理方式,请考虑在UIView上使用此简单类别,该类别可用于基于视图确定视图是“纵向”还是“横向”尺寸。

回顾一下:

  1. 您应该使用大小类来确定何时显示根本不同的UI(例如,“ iPhone风格” UI与“ iPad风格” UI)
  2. 如果在大小类没有变化但容器(父视图)大小发生变化时(例如,在iPad旋转时),如果需要对UI进行较小的调整,请使用viewWillTransitionToSize:withTransitionCoordinator:UIViewController中的回调。
  3. 应用程序中的每个视图都应仅根据已分配给布局的空间来做出布局决策。让视图的自然层次结构将这些信息层叠下来。
  4. 同样,请勿使用statusBarOrientation-本质上是设备级的属性-确定是否为“纵向”和“横向”布局视图。状态栏方向仅应由代码使用,这些代码处理的内容UIWindow实际上位于应用程序的最底层。

5
很好的答案!顺便说一句,您关于AL的youtube视频提供了非常丰富的信息。感谢分享。看看这个!youtube.com/watch?v=taWaW2GzfCI
smileBot 2015年

2
我发现的唯一问题是,有时您想知道设备的方向,而这并不会让您知道。在iPad上,它在状态栏或设备方向值更改之前被调用。您无法确定用户是纵向握持设备还是纵向握持设备。测试也是不可能的,因为嘲笑UIViewControllerTransitionCoordinator是一场噩梦:-(
Darrarski

@Darrarski您是否找到了一种优雅的解决方案来应对这些问题?
Xvolks

viewdidlayoutsubviews那又在哪里呢 我以为viewdidlayoutsubviews是用来捕获由于旋转引起的边界变化。您能详细说明一下吗?
亲爱的

1
如果不使用statusbarorientation,如何区分左侧景观与右侧景观?我需要这种区别。除此之外,还有其他的问题,如这里所描述- stackoverflow.com/questions/53364498/...
迪帕克·夏尔马

17

根据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
}

11

我只是使用通知中心:

添加方向变量(将在末尾说明)

//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语句仅在切换到相反方向时才调用代码。


11
这不是Apple推荐的方法,因为这意味着应用程序中的每个视图都在根据设备的方向来决定如何显示,而不是考虑给定的空间。
smileyborg 2014年

2
苹果公司也没有在8.0中考虑硬件。告诉AVPreview图层,如果它是通过视图控制器显示的,则无需担心方向。不工作,但它固定在8.2
尼克·特纳

superviewDidAppearviewWillDisappear应该叫
安德鲁Bogaevskyi

注意:UIDeviceOrientation!= UIInterfaceOrientation。在我的实验中,statusBarOrientation不可靠。
nnrales

2

从UI角度来看,我认为使用大小类是Apple建议的用于处理不同方向,大小和比例的界面的方法。

请参阅以下部分:特性在此处描述接口的大小类和规模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
2015年

但是,如果我们不是在谈论大小类和UI,而是在谈论AVFoundation,那该怎么办。在录制视频时,在某些情况下,您必须知道viewControllers的方向才能设置正确的元数据。这是简单不可能的。“多才多艺”。
朱利安·F·韦纳特

这不是OP所要询问/谈论的。
亚伦2015年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.