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

yrefmtwq  于 2023-01-27  发布在  iOS
关注(0)|答案(5)|浏览(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
3qpi33ja

3qpi33ja1#

Apple建议使用尺寸分类作为可用屏幕空间的粗略度量,以便用户界面可以显著改变其布局和外观。考虑到iPad在纵向和横向模式下具有相同的尺寸分类(常规宽度、常规高度)。这意味着用户界面在两种方向上应该或多或少相似。
然而,iPad从纵向到横向的变化非常显著,即使size类没有变化,您也可能需要对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:]

    }];
}

很好!现在你可以在旋转开始之前和结束之后得到回调了。但是实际上知道旋转是纵向的还是横向的呢?
苹果建议将旋转看作是父视图大小的简单变化。换句话说,在iPad从纵向旋转到横向的过程中,你可以将其看作是根级别视图,只是将其bounds.size{768, 1024}更改为{1024, 768}。了解了这一点之后,你应该使用传入到上面的viewWillTransitionToSize:withTransitionCoordinator:方法中的size来判断你是旋转到纵向还是横向。
如果您想要一种更无缝的方式将遗留代码迁移到新的iOS 8操作方式,请考虑在UIView上使用this simple category,它可用于根据视图的大小确定视图是"纵向"还是"横向"。
总结一下:
1.您应该使用大小分类来确定何时显示根本不同的UI(例如,"类似iPhone"的UI与"类似iPad"的UI)
1.如果您需要在大小类 * 不 * 更改但容器(父视图)大小更改时(例如iPad旋转时)对UI进行较小的调整,请使用UIViewController中的viewWillTransitionToSize:withTransitionCoordinator:回调。
1.应用中的每个视图都应仅根据其指定的布局空间做出布局决策。让视图的自然层次结构将此信息级联下来。
1.类似地,不要使用statusBarOrientation--它基本上是一个设备级属性--来决定视图的布局是"纵向"还是"横向"。状态栏方向应该只由处理UIWindow之类的代码使用,这些代码实际上位于应用程序的根级别。

dphi5xsq

dphi5xsq2#

基于斯迈尔伯格非常详细(并且被接受)的回答,下面是一个使用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
}
kmynzznz

kmynzznz3#

我只是使用通知中心:

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

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

x6h2sr28

x6h2sr284#

从用户界面的Angular 来看,我相信使用大小类是苹果推荐的处理不同方向、大小和比例的界面的方法。
请参见章节:* 特性描述接口的大小级别和规模 * 此处: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/(信贷:科恩)

wmvff8tz

wmvff8tz5#

解决方法如下:

private var _viewSize: CGSize = .zero
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    
        if _viewSize.equalTo(.zero) {
            _viewSize = self.view.frame.size
        } else if _viewSize.equalTo(self.view.frame.size) == false {
            onViewSizeChanged(from: _viewSize, to: self.view.frame.size)
            _viewSize = self.view.frame.size
        }
    }

    func onViewSizeChanged(from: CGSize, to: CGSize) {
        // self.view changed size after rotation
        // your code... 
    }

相关问题