// // Screen.swift // ┌─┐ ┌───────┐ ┌───────┐ // │ │ │ ┌─────┘ │ ┌─────┘ // │ │ │ └─────┐ │ └─────┐ // │ │ │ ┌─────┘ │ ┌─────┘ // │ └─────┐│ └─────┐ │ └─────┐ // └───────┘└───────┘ └───────┘ // // Created by lee on 2018/1/22. // Copyright © 2018年 lee. All rights reserved. // import Foundation #if os(iOS) import UIKit public class ScreenWrapper { let base: Base public private(set) var value: Base init(_ base: Base) { self.base = base self.value = base } } public protocol ScreenCompatible { associatedtype ScreenCompatibleType var screen: ScreenCompatibleType { get } } extension ScreenCompatible { public var screen: ScreenWrapper { get { return ScreenWrapper(self) } } } extension ScreenWrapper { public func width(_ types: Screen.Width..., is value: Base) -> Self { return width(types, is: value, zoomed: value) } public func width(_ types: Screen.Width..., is value: Base, zoomed: Base) -> Self { return width(types, is: value, zoomed: zoomed) } private func width(_ types: [Screen.Width], is value: Base, zoomed: Base) -> Self { for type in types where Screen.Width.current == type { self.value = Screen.isZoomedMode ? zoomed : value } return self } public func height(_ types: Screen.Height..., is value: Base) -> Self { return height(types, is: value, zoomed: value) } public func height(_ types: Screen.Height..., is value: Base, zoomed: Base) -> Self { return height(types, is: value, zoomed: zoomed) } private func height(_ types: [Screen.Height], is value: Base, zoomed: Base) -> Self { for type in types where Screen.Height.current == type { self.value = Screen.isZoomedMode ? zoomed : value } return self } public func inch(_ types: Screen.Inch..., is value: Base) -> Self { return inch(types, is: value, zoomed: value) } public func inch(_ types: Screen.Inch..., is value: Base, zoomed: Base) -> Self { return inch(types, is: value, zoomed: zoomed) } private func inch(_ types: [Screen.Inch], is value: Base, zoomed: Base) -> Self { for type in types where Screen.Inch.current == type { self.value = Screen.isZoomedMode ? zoomed : value } return self } public func level(_ types: Screen.Level..., is value: Base) -> Self { return level(types, is: value, zoomed: value) } public func level(_ types: Screen.Level..., is value: Base, zoomed: Base) -> Self { return level(types, is: value, zoomed: zoomed) } private func level(_ types: [Screen.Level], is value: Base, zoomed: Base) -> Self { for type in types where Screen.Level.current == type { self.value = Screen.isZoomedMode ? zoomed : value } return self } } public enum Screen { public static var isZoomedMode: Bool { guard !isPlus else { return UIScreen.main.bounds.width == 375 } return UIScreen.main.scale != UIScreen.main.nativeScale } static var size: CGSize { UIScreen.main.bounds.size } static var nativeSize: CGSize { UIScreen.main.nativeBounds.size } static var scale: CGFloat { UIScreen.main.scale } static var nativeScale: CGFloat { UIScreen.main.nativeScale } public enum Width: CGFloat { case unknown = -1 case _320 = 320 case _375 = 375 case _390 = 390 case _414 = 414 case _428 = 428 public static var current: Width { guard !isPlus else { return ._414 } return Width(rawValue: nativeSize.width / scale) ?? .unknown } } public enum Height: CGFloat { case unknown = -1 case _480 = 480 case _568 = 568 case _667 = 667 case _736 = 736 case _812 = 812 case _844 = 844 case _896 = 896 case _926 = 926 public static var current: Height { guard !isPlus else { return ._736 } return Height(rawValue: nativeSize.height / scale) ?? .unknown } } public enum Inch: Double { case unknown = -1 case _3_5 = 3.5 case _4_0 = 4.0 case _4_7 = 4.7 case _5_4 = 5.4 case _5_5 = 5.5 case _5_8 = 5.8 case _6_1 = 6.1 case _6_5 = 6.5 case _6_7 = 6.7 public static var current: Inch { guard !isPlus else { // Plus 机型比较特殊 下面公式无法正确计算出尺寸 return ._5_5 } switch (nativeSize.width / scale, nativeSize.height / scale, scale) { case (320, 480, 2): return ._3_5 case (320, 568, 2): return ._4_0 case (375, 667, 2): return ._4_7 case (375, 812, 3) where UIDevice.iPhoneMini: return ._5_4 case (414, 736, 3): return ._5_5 case (375, 812, 3): return ._5_8 case (414, 896, 2), (390, 844, 3): return ._6_1 case (414, 896, 3): return ._6_5 case (428, 926, 3): return ._6_7 default: return .unknown } } } public enum Level: Int { case unknown = -1 /// 3: 2 case compact /// 16: 9 case regular /// 19.5: 9 case full public static var current: Level { guard !isPlus else { // Plus 机型比较特殊 下面公式无法正确计算出尺寸 return .regular } switch (nativeSize.width / scale, nativeSize.height / scale) { case (320, 480): return .compact case (320, 568), (375, 667), (414, 736): return .regular case (375, 812), (414, 896), (390, 844), (428, 926): return .full default: return .unknown } } } private static var isPlus: Bool { return nativeSize.equalTo(.init(width: 1080, height: 1920)) } } extension Screen { public static var isCompact: Bool { return Level.current == .compact } public static var isRegular: Bool { return Level.current == .regular } public static var isFull: Bool { return Level.current == .full } } extension Int: ScreenCompatible {} extension Bool: ScreenCompatible {} extension Float: ScreenCompatible {} extension Double: ScreenCompatible {} extension String: ScreenCompatible {} extension CGRect: ScreenCompatible {} extension CGSize: ScreenCompatible {} extension CGFloat: ScreenCompatible {} extension CGPoint: ScreenCompatible {} extension UIImage: ScreenCompatible {} extension UIColor: ScreenCompatible {} extension UIFont: ScreenCompatible {} extension UIEdgeInsets: ScreenCompatible {} fileprivate extension UIDevice { static var iPhoneMini: Bool { let temp = ["iPhone13,1", "iPhone14,4"] switch identifier { case "iPhone13,1", "iPhone14,4": return true case "i386", "x86_64", "arm64": return temp.contains(ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "") default: return false } } private static let identifier: String = { var systemInfo = utsname() uname(&systemInfo) let mirror = Mirror(reflecting: systemInfo.machine) let identifier = mirror.children.reduce("") { identifier, element in guard let value = element.value as? Int8, value != 0 else { return identifier } return identifier + String(UnicodeScalar(UInt8(value))) } return identifier } () } #endif