| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- //
- // 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<Base> {
- 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<Self> {
- 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
|