【发布时间】:2017-09-17 04:13:50
【问题描述】:
我正在尝试使用故事板为特定的 iPhone SE 或 5s 使用 AutoLayout 设置约束。
您能否建议一些使用情节提要的屏幕截图来处理仅针对不同 iPhone 的约束?
【问题讨论】:
标签: ios iphone autolayout storyboard
我正在尝试使用故事板为特定的 iPhone SE 或 5s 使用 AutoLayout 设置约束。
您能否建议一些使用情节提要的屏幕截图来处理仅针对不同 iPhone 的约束?
【问题讨论】:
标签: ios iphone autolayout storyboard
iPhone SE 和 iPhone 6/7 具有相同的尺寸等级。因此,您为 SE 创建的所有约束也将应用于 6。 但是您可以从代码中操作它们。检查 UIScreen.main.bounds 并在必要时更新代码中的约束。
【讨论】:
您可以使用变体对 defrance Device 设置约束。但是已经使用了 Xcode 8.0,这是一个新选项 Vary for Traits。
例如,您需要一个在 iPhone 和 iPad 中具有不同宽度的按钮,然后它可以轻松完成并同时查看,而不是早期的 Size 类,其中检查每个布局,我们必须打开预览并选择设备。
我添加了一个固定宽度为 135 的按钮。
现在,如果我们要更改 iPad 的尺寸,请单击右下角的“Vary for Traits”按钮。现在您可以根据需要选择横向或纵向。同时选择高度和宽度复选框。
我现在将宽度常量更改为 500。
然后作为确认,我们需要点击“完成变化”按钮。之后屏幕看起来像
现在,当您返回任何 iPhone 设备时,宽度限制将与之前在 iPhone 设备中设置的相同。
这就是“Vary Traits”的全部内容。我确实接受在使用“Traits”时在不同的 iPhone/iPad + Orientaion 组合之间进行更改时会出现一些约束丢失的错误。
所以为了安全起见,我要求牢记各种屏幕布局的 Size 类值,如
如果您有任何疑问,请告诉我。
【讨论】:
Storyboard 内部 iPhoneSE 和 iPhone6/7 之间的区别是我期待已久的。但不幸的是,我不得不意识到它们具有相同的大小等级,因此(据我所知)不可能为两个内部 Storyboard 设置约束差异。 (如果我错了 - 请告诉我!!)。
但是,您可以在代码中完成。
您可以使用AnchorPoints 或LayoutAnchors 在代码中设置约束。但通常,对于我的大多数情况,以下操作:
我在 UIDevice-ModelNames 周围使用 Switch-case,并将 iPhoneSE 的 Layout-Constraints 设置为与 iPhone6/7(或我想要区分的任何设备)不同。
话虽如此,完全在代码中创建视图(及其约束)通常是一个好主意,而无需故事板。但我认为,对于简单的项目,快速提出 Storybard-Layout 及其约束设置有时仍然很有用。然后我做以下区分设备:
// create the constraint-outlet by CTRL-drag
// one of your defined Constraint-lines from
// Storyboard directly to your Code
@IBOutlet weak var bannerWidthConstraint: NSLayoutConstraint!
// then for example inside viewDidLoad, set the outlet's constant to the value needed...
// Distinguish manually between UIDevices...
override func viewDidLoad() {
switch UIDevice.current.modelName {
case Devices.IPhone5, Devices.IPhone5S, Devices.IPhone5C:
//, Devices.Simulator:
self.bannerWidthConstraint.constant = 73
case Devices.IPhone6, Devices.IPhone6S, Devices.IPhone7, Devices.IPhone8:
//, Devices.Simulator:
self.bannerWidthConstraint.constant = 96
case Devices.IPhone6Plus, Devices.IPhone6SPlus, Devices.IPhone7Plus, Devices.IPhone8Plus:
//, Devices.Simulator:
self.bannerWidthConstraint.constant = 110
case Devices.IPhoneX:
//, Devices.Simulator:
self.bannerWidthConstraint.constant = 96
default:
self.bannerWidthConstraint.constant = 73
}
}
备注:使用模拟器请注意!模拟器有自己的 UIDevice-modelName ,因此您需要取消注释您正在运行模拟器的设备大小中的 Devices.Simulator 注释(即根据您的模拟器运行的目标!)。 --> 注意每个 switch-case 都可以是 Simulator-Device !!
并且不要忘记在代码库中的某处定义您的设备: (--> 当然,当新的 Apple 设备出现时,您需要更新这些...)
public enum Devices: String {
case IPodTouch5
case IPodTouch6
case IPhone4
case IPhone4S
case IPhone5
case IPhone5C
case IPhone5S
case IPhone6
case IPhone6Plus
case IPhone6S
case IPhone6SPlus
case IPhone7
case IPhone7Plus
case IPhoneSE
case IPhone8
case IPhone8Plus
case IPhoneX
case IPad2
case IPad3
case IPad4
case IPad5
case IPadAir
case IPadAir2
case IPadMini
case IPadMini2
case IPadMini3
case IPadMini4
case IPadPro_9_7
case IPadPro_12_9
case IPadPro_12_9_2ndGen
case IPadPro_10_5
case AppleTV_5_3
case AppleTV_6_2
case HomePod
case Simulator
case Other
}
还有……
public extension UIDevice {
public var modelName: Devices {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8 , value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
switch identifier {
case "iPod5,1": return Devices.IPodTouch5
case "iPod7,1": return Devices.IPodTouch6
case "iPhone3,1", "iPhone3,2", "iPhone3,3": return Devices.IPhone4
case "iPhone4,1": return Devices.IPhone4S
case "iPhone5,1", "iPhone5,2": return Devices.IPhone5
case "iPhone5,3", "iPhone5,4": return Devices.IPhone5C
case "iPhone6,1", "iPhone6,2": return Devices.IPhone5S
case "iPhone7,2": return Devices.IPhone6
case "iPhone7,1": return Devices.IPhone6Plus
case "iPhone8,1": return Devices.IPhone6S
case "iPhone8,2": return Devices.IPhone6SPlus
case "iPhone9,1", "iPhone9,3": return Devices.IPhone7
case "iPhone9,2", "iPhone9,4": return Devices.IPhone7Plus
case "iPhone8,4": return Devices.IPhoneSE
case "iPhone10,1", "iPhone10,4": return Devices.IPhone8
case "iPhone10,2", "iPhone10,5": return Devices.IPhone8Plus
case "iPhone10,3", "iPhone10,6": return Devices.IPhoneX
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return Devices.IPad2
case "iPad3,1", "iPad3,2", "iPad3,3": return Devices.IPad3
case "iPad3,4", "iPad3,5", "iPad3,6": return Devices.IPad4
case "iPad4,1", "iPad4,2", "iPad4,3": return Devices.IPadAir
case "iPad5,3", "iPad5,4": return Devices.IPadAir2
case "iPad6,11", "iPad6,12": return Devices.IPad5
case "iPad2,5", "iPad2,6", "iPad2,7": return Devices.IPadMini
case "iPad4,4", "iPad4,5", "iPad4,6": return Devices.IPadMini2
case "iPad4,7", "iPad4,8", "iPad4,9": return Devices.IPadMini3
case "iPad5,1", "iPad5,2": return Devices.IPadMini4
case "iPad6,3", "iPad6,4": return Devices.IPadPro_9_7
case "iPad6,7", "iPad6,8": return Devices.IPadPro_12_9
case "iPad7,1", "iPad7,2": return Devices.IPadPro_12_9_2ndGen
case "iPad7,3", "iPad7,4": return Devices.IPadPro_10_5
case "AppleTV5,3": return Devices.AppleTV_5_3
case "AppleTV6,2": return Devices.AppleTV_6_2
case "AudioAccessory1,1": return Devices.HomePod
case "i386", "x86_64": return Devices.Simulator
default: return Devices.Other
}
}
}
【讨论】:
这不是很好,但至少比用代码做所有事情要容易一些。
所以,例如如果你想为 LoginViewController 设置不同的约束,你可以创建两个 xib:LoginViewControllerSE.xib(用于 SE)和 LoginViewController.xib(用于其他手机),然后创建初始化程序:
init() {
if UIDevice.current.modelName == Devices.IPhoneSE {
super.init(nibName: "LoginViewControllerSE", bundle: nil)
} else {
super.init(nibName: nil, bundle: nil)
}
}
【讨论】: