以编程方式为 iPhone 和 iPad 布局 UI 的最佳实践

Best Practice for laying out UI Programmatically for both iPhone and iPad

寻找一个干净的解决方案来以编程方式布局 UI 并使其在每台设备上看起来都正确。我尝试扩展 CGFloat 以根据设备缩放数字

extension CGFloat {
    func scale() {
        // Modifies self by multiplies by the ratio between the initial screen size and the desired screen size
    }
}

// usage
view.widthAnchor.constraint(equalToConstant: 20.scale())

我也试过为 iPhone 和 iPad 创建两组不同的约束,并根据应用 运行 在哪个设备上激活它们,但这似乎不必要的冗长。

我如何布置我的 UI 以便它可以在所有设备上运行而无需复杂的解决方法。我应该避免某些类型的约束吗? (例如,不是设置 width/height 常量,而是将它们设置为屏幕(或其他视图)width/height 的倍数?)

编辑:我不想过度解释我自己的情况,所以让我重新提问。在为 iPhone 和 iPad 设计的应用程序中设置约束的最佳实践是什么?仅检查设备是否为 iPad 是否是一种不好的做法,如果是,则仅对 iPad 进行约束,如果不是,则仅对 iPhone.[= 进行约束14=]

我通常先获取屏幕的大小,然后使用 width/height 的百分比作为框架

height = view.bounds.height
width = view.bounds.width
mybutton.frame = CGRect(x: width * 0.05, y: height * 0.02, width: width * 0.3, height: height * 0.1)

您的问题,as-is,无法回答...

您的应用程序是做什么的?如果是照片 slide-show,将 imageView 限制为完整视图并将其内容模式设置为 scale-fit。瞧!它 "looks good" 在所有设备上!

如果您的应用比这更复杂,您可能需要使用 all 约束类型:相对元素对彼此;彼此相等; relative/equal 不断调整; relative/equal 乘数调整;等。并且您可能需要基于设备+方向的不同布局(不仅仅是不同的大小),在这种情况下,您还需要利用 size-class-variations.

此外,将应用程序添加到"look right on every device"涉及很多,很多MUCH 比应用约束更多。

  • 应用程序应该使用标签栏吗?
  • 导航栏?
  • 它们的组合?
  • 也没有?
  • 应该使用text-buttons还是image-buttons?
  • 是否应该针对辅助功能和动态字体进行调整?
  • 在小屏幕和大屏幕上 运行 时,它甚至可能具有不同的功能吗?

一般来说,您的第一步应该是 hand-drawing 每个屏幕和您希望拥有的 UI 元素 - 包括 activity "flow" - 尺寸和变化方向,因此您从一开始就在设计最好的 UI/UX。届时,您将开始实际 UI 构建。

请记住,有些人无法制作 "Hellow World" 应用程序,但可以很好 生活作为 "App Designers."

说了这么多,但是...您几乎 当然 不应该采用的一种方法是:

view.widthAnchor.constraint(equalToConstant: 20.scale())

编辑

这是一个基于这篇文章的简单示例:https://www.raywenderlich.com/1343912-adaptive-layout-tutorial-in-ios-12-getting-started

一个简单的天气应用程序 - 限制设置使其在所有 iPhone 和 iPad 模型上看起来相似:

但是,当您旋转 phone 时会发生什么?

小小的云看起来不太好。添加trait-variations / size-classes,我们可以得到:


并且,尝试回答您编辑的问题:"Is it bad practice to just check if the device is an iPad..."?

是的。建议针对 trait-variations / size-classes 进行设计,以便您的应用程序在所有配置中看起来都符合您的要求(希望 future-proof 也适用于下一个推出的设备)。

Is it bad practice to just check if the device is an iPad, and if it is, have constraints just for iPad, and, if not, have constraints for just iPhone.

如果您打算支持 Split-View,那绝对不行。实现和处理它的代码总是会有点冗长。这里没有单行代码来实现你想要的。

在您的 -[UIViewController viewDidLoad] 方法中,您希望使用控制器视图可用的基本特征集合来设置视图。这是你的起点。

当您的应用程序 windows 被 OS 调整大小时(想象一下,将横向模式下的全屏应用程序变成拆分大小的应用程序,占据屏幕的三分之一): -[UIViewController traitCollectionDidChange:] 方法在您的视图控制器上被调用。这是您更新布局约束的地方。

您可以而且应该将您的布局逻辑封装在一个方法中,并从 -[UIViewController viewDidLoad]-[UIViewController traitCollectionDidChange:] 调用它。

在这种方法中,我不建议检查主机设备是否是iPad。您特别想查看活动特征集合的 horizontalSizeClass & verticalSizeClass 属性以确定布局约束的值。

如需了解更多信息,建议您阅读以下文档:
1. https://developer.apple.com/documentation/uikit/uitraitcollection?language=objc
2. https://developer.apple.com/documentation/uikit/uitraitenvironment/1623516-traitcollectiondidchange?language=objc

第二个 link 有一个关于如何检查是否需要更新约束的简单示例。