本文介绍了如何在 iOS 8/Swift 中处理屏幕尺寸/方向变化的 NSLayoutConstraints?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用 IB 约束和 NSLayoutConstraint?

我想以编程方式微调我的 Interface Builder Storyboard 布局,因为我无法仅在 Interface Builder 中使用约束来实现所需的布局.

I want to programmatically fine-tune my Interface Builder Storyboard layout, as I can't achieve desired layout with constraints in Interface Builder alone.

iPhone 4S 和 iPhone 6 Plus 对我的 iOS 8 布局尤其具有挑战性.

The iPhone 4S and iPhone 6 Plus are particularly challenging for my iOS 8 layouts.

问题:

  • 如何在 UIViewController 出现时找到屏幕尺寸?

我如何检测方向变化 &iOS 8 中的最终屏幕尺寸?

How do I detect orientation changes & resulting screen dimensions in iOS 8?

如何以编程方式修改布局约束?

我如何以编程方式处理 IB size classes?

How do I deal with IB size classes programmatically?

也许通过在 IB 中加权"组件,我可以补偿 iPhone 6 Plus 尺寸等级的布局问题.但这似乎比以编程方式进行一些调整更具挑战性.

Maybe by "weighting" components in IB, I could compensate for layout problems with iPhone 6 Plus size class. But it seems potentially more challenging than making a few tweaks programmatically.

iOS 8 支持的设备a是不同屏幕尺寸的泥潭

iOS 8 应用程序仍然需要支持 iPhone 4S,虽然它的微小屏幕非常可笑.对于更适合大 iPhone 屏幕的应用来说,要在 4S 上获得满意的效果是相当大的压力,而且几乎是荒谬的挑战.

The iPhone 4S, with its ridiculously tiny screen, is still required to be supported by iOS 8 apps. It's quite a squeeze, and challenging to an almost absurd degree for apps better suited to larger iPhone screens to be satisfactory on the 4S.

iPhone 6 Plus 实际上是 iPad 的mini-mini",只是纵横比更窄.相对庞大的 iPhone 6 plus 需要比其他 iPhone 更均匀/宽敞的组件分布.然而,Interface Builder 大小类并没有很好地涵盖 iPhone 6 Plus(到目前为止).

And iPhone 6 Plus is virtually an iPad "mini-mini", except for its tighter aspect ratio. The relatively gargantuan iPhone 6 plus requires a more even/spacious component distribution than other iPhones. Yet Interface Builder size classes don't cover the iPhone 6 Plus very well (so far).

推荐答案

这是 iOS 8/Swift 代码示例的一种方法

Here's one approach with iOS 8/Swift code example

• 使用 IBOutlets 并修改适当的出口约束:

我发现以编程方式修改基于约束的布局的最佳方法是为我想要修改的每个约束创建一个 IBOutlet,而不是产生开销编写代码来定位/添加/以编程方式删除/替换约束,尤其是在界面生成器布局中使用大小类时.替换约束在使用大小类"时是一个主要的麻烦(谷歌它的定义).您真的必须知道自己在做什么才能使约束替换正常工作,而且开销要高得多.

The best way I've found to modify constraint-based layouts programmatically is to make an IBOutlet for each constraint I want to modify in place, rather than incur overhead writing code to locate/add/remove/replace constraints programmatically, particularly when size classes are used in the Interface Builder layout. Replacing constraints is a major hassle when "size classes" are used (Google its definition). You really have to know what you're doing to make constraint replacement work right, plus, and there's considerably higher overhead.

• 避免使用 IB 布局约束的乘数属性:

根据需要定位更大的占位符/容器视图来简化复杂的布局,将场景向下过渡到更详细的视图.战略性地设计约束,因此您只需在运行时通过其出口以编程方式调整尽可能少的约束以获得最佳布局.如果可能,请单独使用 NSLayoutConstraintconstant 属性,而不是篡改 NSLayoutConstraintmultiplier 属性,因为 constant 可以在运行时修改,但是 multiplier 是只读的,需要替换约束来修改它.如果您使用 multiplier 属性是因为您需要根据其他视图的大小或位置按比例调整约束,您可以在代码中进行乘法并将其应用于 constant 在运行时,而不是依赖 NSLayoutConstraint multiplier 属性.

Simplify complex layouts by positioning larger placeholder/container views, as necessary, staging the scene down to toward more detailed view. Strategically design constraints so you only have to tweak the fewest constraints possible programmatically via their outlet at runtime for optimal layout. Do so using NSLayoutConstraint's constant property alone, if possible, rather than tampering with NSLayoutConstraint's multiplier property, because constant can be modified at runtime, but multiplier is readonly, requiring constraint replacement to modify it. If you are using the multiplier property because you need the constraints to adjust proportionally to the size or positions of other views, you can do the multiplication in your code and apply it to constant at runtime, rather than rely on NSLayoutConstraint multiplier property.

• 每个 IB 约束使用单一大小分类常量:

如果您使用的是尺寸类,在 Interface Builder 中,请务必定义单独约束,每个约束只有一个单个尺寸类特定的常量 以便您为 每个 单独的尺寸分类约束分配一个出口,而不是尝试将多个尺寸分类的常量聚合到单个约束中.尽管 Interface Builder 允许您将多个常量添加到一个约束定义中,但 NSLayoutConstraint 本身仅提供一个单个 常量财产.这意味着多个 NSLayoutConstraint 实例将在运行时由单个可见的 Interface Builder 约束定义产生,如果它附加了多个大小类常量.尝试在运行时定位未输出的约束并对其进行调整而不会遇到问题,这比您想象的要棘手.

If you're using size classes, in Interface Builder, be sure to define individual constraints, each with only a single size-class specific constant so that you assign an outlet to each individual size-classed constraint, rather trying than aggregating constants for multiple size classes into a single constraint. Though Interface Builder will let you add multiple constants to one constraint definition, NSLayoutConstraint itself only provides only a single constant property. This implies that multiple NSLayoutConstraint instances will result at runtime from a single visible Interface Builder constraint definition, if it has multiple size class constants attached to it. It gets trickier than you might assume to try to locate un-outleted constraints at runtime and tweak them without running into problems.

• 谨防以编程方式混淆 IB 约束的运行时问题:

如果您确实尝试在运行时以编程方式定位/修改/删除/替换约束,当涉及大小类时,请为耗时的混乱冲突和错误做好准备.我发现 iOS 使用黑盒逻辑给图片带来了意想不到的幽灵"约束,阻碍了进行布局更改的尝试.iOS 可能会生成冲突警告,有时即使您以编程方式删除了约束(为什么这些约束仍在 iOS 的处理逻辑中??!!!)iOS 有时能够打破并修复约束运行时发生冲突,但即使 iOS 解决了冲突,而且结果看起来不错,但 Apple 明确将此类冲突(产生 Xcode 控制台错误消息)视为用户编码错误.

If you do try to programmatically locate/modify/remove/replace constraints at runtime, when size classes are involved, brace yourself for time-consuming confusing conflicts and errors. I've found iOS brings 'ghost' constraints into the picture that are unexpected using black-box logic, thwarting attempts to make layout changes. Conflict warnings may be generated by iOS, sometimes even with constraints that you programmatically deleted (e.g. why are those constraints still in iOS's processing logic??!!!) iOS will sometimes be able to break and fix constraint conflicts at runtime, but even if a conflict is broken by iOS, and it all winds up looking good, such conflicts (that produce Xcode console error messages) are explicitly considered user coding bugs by Apple.

Swift/iOS 8 代码示例:

@IBOutlet var keypadPlaceholder      : UIView!
@IBOutlet var textualDatePlaceholder : UIView!
@IBOutlet var keypadVconstraint      : NSLayoutConstraint!
@IBOutlet var textualDateVConstraint : NSLayoutConstraint!
@IBOutlet var datePickerVConstraint  : NSLayoutConstraint!

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    adjustViewLayout(size)
}
override func viewWillAppear(animated: Bool) {
    adjustViewLayout(UIScreen.mainScreen().bounds.size)
}
func adjustViewLayout(size: CGSize) {
    println("height: \(size.height), width: \(size.width)")

    switch(size.width, size.height) {
    case (480, 320):                        // iPhone 4S in landscape
        keypadPlaceholder.hidden = false
        textualDatePlaceholder.hidden = false
    case (320, 480):                        // iPhone 4S in portrait
        keypadPlaceholder.hidden = true
        textualDatePlaceholder.hidden = true
    case (414, 736):                        // iPhone 6 Plus in portrait
        textualDateVConstraint.constant = 105
        datePickerVConstraint.constant = 50
        keypadVconstraint.constant = 50
        view.setNeedsLayout()
    case (736, 414):                        // iphone 6 Plus in landscape
        textualDateVConstraint.constant = 80
        datePickerVConstraint.constant = 3
        keypadVconstraint.constant = 3
        view.setNeedsLayout()
    default:
        break
    }
}

这篇关于如何在 iOS 8/Swift 中处理屏幕尺寸/方向变化的 NSLayoutConstraints?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 07:14