首页 文章

XCode:如何在横向和纵向模式之间更改视图布局

提问于
浏览
5

在纵向模式下,我从视图控制器的顶部到底部有四个视图(参见图像) .

portrait view

然后我想在设备转换为横向时更改视图相对于彼此的位置(参见图2) .
landscape view

我希望视图4与视图2和3一起移动,并且它们都位于视图1下方 .

一些布局条件:

  • 视图1以横向和纵向方式附加到视图控制器的顶部 .

  • 视图4以纵向模式连接到视图控制器的左,右和底边距 .

  • 视图2,3和4在纵向视图中水平居中 .

实现不同布局的最佳方法是什么?

最优雅的解决方案是在视图控制器代码中引用约束并在viewWillTransition中激活和停用它们吗?或者有没有办法使用各种特性来实现这一点(我可以想象水平居中的视图2,3和4会使这很难实现,以及在横向模式下为视图4添加新的约束)?

2 回答

  • 19

    我们过去常常设置不同的约束集,并根据方向变化激活/停用它们 . 但是现在可以使用大小类和“因性状而异” .

    例如,我从一个简单的视图开始,选择一个紧凑的宽度大小类,然后选择“Vary for traits”:

    enter image description here

    然后我添加适当的约束并单击“完成变化”:

    enter image description here

    然后我选择“常规宽度大小类”并重复该过程(“对特征变化”,添加约束,单击“完成变化”:

    enter image description here

    然后,您最终得到一个场景,该场景将对紧凑宽度大小类和常规宽度大小类具有完全不同的约束集 . 即当我运行应用程序时,如果设备旋转,则会激活新约束:

    enter image description here

    有关更多信息,请参阅有关自适应布局的WWDC 2016视频:

  • 1

    我使用约束数组并根据方向激活/停用 .

    var p = [NSLayoutConstraint]()
    var l = [NSLayoutConstraint]()
    var initialOrientation = true
    var isInPortrait = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // add any subviews here
        view.turnOffAutoResizing()        
        // add constraints here....
        //    common constraints you can set their isActive = true
        //    otherwise, add in to portrait(p) and landscape(l) arrays
    }
    
    override func viewWillLayoutSubviews() {
        super.viewDidLayoutSubviews()
        if initialOrientation {
            initialOrientation = false
            if view.frame.width > view.frame.height {
                isInPortrait = false
            } else {
                isInPortrait = true
            }
            view.setOrientation(p, l)
        } else {
            if view.orientationHasChanged(&isInPortrait) {
                view.setOrientation(p, l)
            }
        }
    }
    extension UIView {
        public func turnOffAutoResizing() {
            self.translatesAutoresizingMaskIntoConstraints = false
            for view in self.subviews as [UIView] {
               view.translatesAutoresizingMaskIntoConstraints = false
            }
        }
        public func orientationHasChanged(_ isInPortrait:inout Bool) -> Bool {
            if self.frame.width > self.frame.height {
                if isInPortrait {
                    isInPortrait = false
                    return true
                }
            } else {
                if !isInPortrait {
                    isInPortrait = true
                    return true
                }
            }
            return false
        }
        public func setOrientation(_ p:[NSLayoutConstraint], _ l:[NSLayoutConstraint]) {
            NSLayoutConstraint.deactivate(l)
            NSLayoutConstraint.deactivate(p)
            if self.bounds.width > self.bounds.height {
                NSLayoutConstraint.activate(l)
            } else {
                NSLayoutConstraint.activate(p)
            }
        }
    }
    

    我需要区分肖像或风景 require 使用大小类以外的东西,因为我的应用程序是通用的,iPad(除非使用拆分或滑出视图)总是正常大小 . 此外,您可能会使用 viewWillTransistion(toSize:)viewDidLoadSubviews() 而不是'viewWillLoadSubviews()` - 但总是测试,因为这些可能会在方向更改时执行多次!

相关问题