├── .swift-version
├── InspireDemo
├── InspireDemo
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── MyInspire.swift
│ ├── theme.json
│ ├── Info.plist
│ ├── NewVC.swift
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── SceneDelegate.swift
│ └── ViewController.swift
└── InspireDemo.xcodeproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── project.pbxproj
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── Package.swift
├── LICENSE
├── Sources
└── Inspire
│ ├── InLayer.swift
│ ├── InWindow.swift
│ ├── InFont.swift
│ ├── InCache.swift
│ ├── InColor.swift
│ ├── Inspire.swift
│ └── InLayout.swift
├── README.md
└── .gitignore
/.swift-version:
--------------------------------------------------------------------------------
1 | 5.0
2 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo/MyInspire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MyInspire.swift
3 | // InspireDemo
4 | //
5 | // Created by xaoxuu on 2022/8/30.
6 | //
7 |
8 | import Foundation
9 | import Inspire
10 |
11 | let myInspire = Inspire.current
12 |
13 | extension Inspire {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.6
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "Inspire",
7 | platforms: [.iOS(.v9)],
8 | products: [
9 | .library(name: "Inspire", targets: ["Inspire"]),
10 | ],
11 | targets: [
12 | .target(
13 | name: "Inspire",
14 | dependencies: []
15 | )
16 | ]
17 | )
18 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo/theme.json:
--------------------------------------------------------------------------------
1 | {
2 | "Color" : {
3 | "theme" : "#FF9898FF",
4 | "accent" : "#1BCBFAFF",
5 | "background" : "#666666"
6 | },
7 | "Font" : {
8 | "title" : "AvenirNext-Bold",
9 | "number" : "Courier",
10 | "body" : "ChalkboardSE-Regular",
11 | "code" : "Menlo-Regular"
12 | },
13 | "Layout" : {
14 | "margin" : "16.0",
15 | "padding" : "8.0",
16 | "cornerRadius" : {
17 | "small" : "4.0",
18 | "regular" : "8.0",
19 | "large" : "16.0",
20 | "medium" : "12.0"
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UIApplicationSceneManifest
6 |
7 | UIApplicationSupportsMultipleScenes
8 |
9 | UISceneConfigurations
10 |
11 | UIWindowSceneSessionRoleApplication
12 |
13 |
14 | UISceneConfigurationName
15 | Default Configuration
16 | UISceneDelegateClassName
17 | $(PRODUCT_MODULE_NAME).SceneDelegate
18 | UISceneStoryboardFile
19 | Main
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Mr. X
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Sources/Inspire/InLayer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InLayer.swift
3 | // Inspire
4 | //
5 | // Created by xaoxuu on 2022/6/23.
6 | // Copyright © 2022 Titan Studio. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public extension CALayer {
12 |
13 | /// 切部分圆角
14 | /// - Parameters:
15 | /// - corners: 位置
16 | /// - cornerRadii: 半径
17 | func cornerRadius(corners: UIRectCorner, cornerRadii: CGFloat) {
18 | let maskPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: cornerRadii, height: cornerRadii))
19 | let maskLayer = CAShapeLayer()
20 | maskLayer.frame = self.bounds
21 | maskLayer.path = maskPath.cgPath
22 | self.mask = maskLayer
23 | }
24 |
25 | var cornerRadiusWithContinuous: CGFloat {
26 | get { cornerRadius }
27 | set {
28 | cornerRadius = newValue
29 | if #available(iOS 13.0, *) {
30 | cornerCurve = .continuous
31 | } else {
32 | // Fallback on earlier versions
33 | }
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/Sources/Inspire/InWindow.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InWindow.swift
3 | // Inspire
4 | //
5 | // Created by xaoxuu on 2021/7/20.
6 | // Copyright © 2021 xaoxuu.com. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @available(iOS 13.0, *)
12 | public extension UIWindowScene {
13 |
14 | /// 当前的 WindowScene
15 | static var currentWindowScene: UIWindowScene? {
16 | UIApplication.shared.connectedScenes.first { scene in
17 | guard let ws = scene as? UIWindowScene else { return false }
18 | return ws.activationState == .foregroundActive
19 | } as? UIWindowScene
20 | }
21 |
22 | }
23 |
24 | public extension UIViewController {
25 |
26 | /// 当前 window 的根控制器
27 | static var currentRootViewController: UIViewController? {
28 | if #available(iOS 13.0, *) {
29 | return UIWindowScene.currentWindowScene?.windows.first?.rootViewController
30 | } else {
31 | return UIApplication.shared.windows.first { window in
32 | window.isHidden == false && window.frame == UIScreen.main.bounds
33 | }?.rootViewController
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo/NewVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NewVC.swift
3 | // InspireDemo
4 | //
5 | // Created by xaoxuu on 2022/8/30.
6 | //
7 |
8 | import UIKit
9 |
10 | class NewVC: UIViewController {
11 |
12 | override func viewDidLoad() {
13 | super.viewDidLoad()
14 |
15 | // Do any additional setup after loading the view.
16 |
17 | let btn = UIButton(type: .system)
18 | btn.frame = CGRect(x: 20, y: 20, width: 100, height: 100)
19 | btn.setTitle("dismiss", for: .normal)
20 | btn.addTarget(self, action: #selector(self.dismiss(_:)), for: .touchUpInside)
21 | view.addSubview(btn)
22 | }
23 |
24 | @objc func dismiss(_ sender: UIButton) {
25 | dismiss(animated: true, completion: nil)
26 | }
27 | override func touchesBegan(_ touches: Set, with event: UIEvent?) {
28 |
29 | let mask = UIView()
30 | mask.backgroundColor = UIColor.red.withAlphaComponent(0.1)
31 | let safeAreaInsets = ipr.layout.safeAreaInsets(for: self)
32 | print(safeAreaInsets)
33 | mask.frame = .init(x: safeAreaInsets.left, y: safeAreaInsets.top, width: view.bounds.width - safeAreaInsets.left - safeAreaInsets.right, height: view.bounds.height - safeAreaInsets.top - safeAreaInsets.bottom)
34 | view.insertSubview(mask, at: 0)
35 | }
36 |
37 |
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // InspireDemo
4 | //
5 | // Created by xaoxuu on 2022/8/30.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 |
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 | // Override point for customization after application launch.
17 | return true
18 | }
19 |
20 | // MARK: UISceneSession Lifecycle
21 |
22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
23 | // Called when a new scene session is being created.
24 | // Use this method to select a configuration to create the new scene with.
25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
26 | }
27 |
28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
29 | // Called when the user discards a scene session.
30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
32 | }
33 |
34 |
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Inspire
2 |
3 | 基于主题的Swift开发基础工具包
4 |
5 | 包含颜色、字体、布局等,可配置可缓存
6 |
7 |
8 |
9 | ## 特性
10 |
11 | ### 可缓存的
12 |
13 | - App 的样式参数(颜色、字体、布局)存储于 json 文件中。
14 |
15 | ### 可配置的
16 |
17 | - 可由用户修改主题参数并保存或者分享。
18 |
19 | ### 提供便利
20 |
21 | - 便捷的方式获取屏幕布局参数、如各边安全区域尺寸,便于机型适配。
22 |
23 |
24 | ## 开始使用
25 |
26 | ### 使用 CocoaPods
27 |
28 | ```ruby 在 Podfile 中添加:
29 | pod 'Inspire'
30 | ```
31 |
32 | ```sh 然后执行:
33 | pod install
34 | ```
35 |
36 | ### 使用 Package.swift
37 |
38 | 在 Package.swift 中声明依赖项:
39 |
40 | ```swift
41 | .package(url: "https://github.com/xaoxuu/Inspire.git", from: "1.1.0"),
42 | ```
43 |
44 |
45 | ## 用法示例
46 |
47 |
48 |
49 | ### 颜色
50 |
51 | ```swift
52 | view.backgroundColor = .background
53 | view.tintColor = .accent
54 | ```
55 |
56 | ### 字体
57 |
58 | ```swift
59 | let lb = UILabel()
60 | lb.font = .regular(15)
61 | lb.font = .bold(20, for: .title)
62 | lb.font = .regular(14, for: .code)
63 | ```
64 |
65 | ### 边距
66 |
67 |
68 | ```swift
69 | let topMargin = layout.topBarHeight(for: self)
70 | let bottomMargin = layout.bottomBarHeight(for: self)
71 | let safeArea = layout.safeAreaInsets(for: self)
72 | let safeArea2 = Inspire.shared.screen.safeAreaInsets
73 | ```
74 |
75 | ```swift
76 | let layout = Inspire.shared.layout
77 | view.frame.size.height = layout.rowHeight
78 | view.layer.cornerRadius = layout.cornerRadius.large
79 | ```
80 |
81 | ### 缓存
82 |
83 | ```swift
84 | // 保存
85 | Inspire.shared.cache()
86 | Inspire.shared.cache(named: "myTheme")
87 | // 读取
88 | let ipr = Inspire.init("myTheme")
89 | ```
90 |
91 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | # Package.resolved
41 | .build/
42 |
43 | # CocoaPods
44 | #
45 | # We recommend against adding the Pods directory to your .gitignore. However
46 | # you should judge for yourself, the pros and cons are mentioned at:
47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
48 | #
49 | # Pods/
50 |
51 | # Carthage
52 | #
53 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
54 | # Carthage/Checkouts
55 |
56 | Carthage/Build
57 |
58 | # fastlane
59 | #
60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
61 | # screenshots whenever they are needed.
62 | # For more information about the recommended setup visit:
63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
64 |
65 | fastlane/report.xml
66 | fastlane/Preview.html
67 | fastlane/screenshots/**/*.png
68 | fastlane/test_output
69 |
70 | .DS_Store
71 | Pods
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "2x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "83.5x83.5"
82 | },
83 | {
84 | "idiom" : "ios-marketing",
85 | "scale" : "1x",
86 | "size" : "1024x1024"
87 | }
88 | ],
89 | "info" : {
90 | "author" : "xcode",
91 | "version" : 1
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/Sources/Inspire/InFont.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Font.swift
3 | // Inspire
4 | //
5 | // Created by xaoxuu on 2019/3/26.
6 | // Copyright © 2019 xaoxuu.com. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public extension UIFont {
12 |
13 | internal class func getFontName(_ style: Inspire.InFont.Scheme = .body) -> String {
14 | let font = Inspire.current.font
15 | switch style {
16 | case .title:
17 | return font.title
18 | case .body:
19 | return font.body
20 | case .number:
21 | return font.number
22 | case .code:
23 | return font.code
24 | }
25 | }
26 |
27 | class func regular(_ size: CGFloat, for style: Inspire.InFont.Scheme = .body) -> UIFont {
28 | let desc = UIFontDescriptor.init(fontAttributes: [.name : getFontName(style)])
29 | return UIFont.init(descriptor: desc, size: size)
30 | }
31 |
32 | class func bold(_ size: CGFloat, for style: Inspire.InFont.Scheme = .body) -> UIFont {
33 | return regular(size, for: style).boldFont()
34 | }
35 |
36 | func boldFont() -> UIFont {
37 | let fontDesc = fontDescriptor
38 | let fontDescriptorSymbolicTraits = UIFontDescriptor.SymbolicTraits.init(rawValue:(fontDesc.symbolicTraits.rawValue | UIFontDescriptor.SymbolicTraits.traitBold.rawValue))
39 | if let boldFontDesc = fontDesc.withSymbolicTraits(fontDescriptorSymbolicTraits) {
40 | return UIFont.init(descriptor: boldFontDesc, size: pointSize)
41 | } else {
42 | return self
43 | }
44 | }
45 |
46 | }
47 |
48 | public extension Inspire {
49 |
50 | static func configDefault(font: String, for scheme: Inspire.InFont.Scheme) {
51 | switch scheme {
52 | case .title:
53 | if Inspire.shared.font.title == "" {
54 | Inspire.shared.font.title = font
55 | }
56 | case .body:
57 | if Inspire.shared.font.body == "" {
58 | Inspire.shared.font.body = font
59 | }
60 | case .number:
61 | if Inspire.shared.font.number == "" {
62 | Inspire.shared.font.number = font
63 | }
64 | case .code:
65 | if Inspire.shared.font.code == "" {
66 | Inspire.shared.font.code = font
67 | }
68 | }
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/Sources/Inspire/InCache.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InCache.swift
3 | // Inspire
4 | //
5 | // Created by xaoxuu on 2019/3/28.
6 | // Copyright © 2019 xaoxuu.com. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // MARK: - 缓存主题
12 | public extension Inspire {
13 |
14 | /// 缓存路径
15 | ///
16 | /// - Parameter file: 文件名
17 | /// - Returns: 路径
18 | internal static func cachePath(for file: String = "theme.json") -> String {
19 | if let docPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
20 | let path = docPath + "/Inspire"
21 | if FileManager.default.fileExists(atPath: path) == false {
22 | do {
23 | try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
24 | } catch {
25 | print(error.localizedDescription)
26 | }
27 | }
28 | return NSString.init(string: path).appendingPathComponent(file) as String
29 | } else {
30 | print("获取文档路径失败!")
31 | return ""
32 | }
33 | }
34 |
35 | /// 缓存当前主题
36 | ///
37 | /// - Parameter named: 主题名
38 | func cache(named: String = "theme"){
39 | do {
40 | let data = try JSONSerialization.data(withJSONObject: export(), options: .prettyPrinted)
41 | let url = URL.init(fileURLWithPath: Inspire.cachePath(for: named+".json"))
42 | try data.write(to: url, options: .atomic)
43 | } catch {
44 | print(error.localizedDescription)
45 | }
46 | }
47 |
48 | /// 从缓存中恢复主题
49 | ///
50 | /// - Parameter named: 主题名
51 | static func restore(_ named: String = "theme"){
52 | Inspire.apply(Inspire(named))
53 | }
54 |
55 | /// 根据缓存的主题名创建主题
56 | ///
57 | /// - Parameter named: 缓存的主题名
58 | init(_ named: String = "theme") {
59 | do {
60 | let data = try Data.init(contentsOf: URL.init(fileURLWithPath: Inspire.cachePath(for: named+".json")))
61 | let dict = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
62 | if let d = dict as? [String: Any] {
63 | self.init(d)
64 | } else {
65 | self.init()
66 | }
67 | } catch {
68 | print(error.localizedDescription)
69 | self.init()
70 | }
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // InspireDemo
4 | //
5 | // Created by xaoxuu on 2022/8/30.
6 | //
7 |
8 | import UIKit
9 | import Inspire
10 | let ipr = Inspire.shared
11 |
12 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
18 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
19 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
20 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
21 | guard let _ = (scene as? UIWindowScene) else { return }
22 | }
23 |
24 | func sceneDidDisconnect(_ scene: UIScene) {
25 | // Called as the scene is being released by the system.
26 | // This occurs shortly after the scene enters the background, or when its session is discarded.
27 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
28 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
29 | }
30 |
31 | func sceneDidBecomeActive(_ scene: UIScene) {
32 | // Called when the scene has moved from an inactive state to an active state.
33 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
34 | }
35 |
36 | func sceneWillResignActive(_ scene: UIScene) {
37 | // Called when the scene will move from an active state to an inactive state.
38 | // This may occur due to temporary interruptions (ex. an incoming phone call).
39 | }
40 |
41 | func sceneWillEnterForeground(_ scene: UIScene) {
42 | // Called as the scene transitions from the background to the foreground.
43 | // Use this method to undo the changes made on entering the background.
44 | }
45 |
46 | func sceneDidEnterBackground(_ scene: UIScene) {
47 | // Called as the scene transitions from the foreground to the background.
48 | // Use this method to save data, release shared resources, and store enough scene-specific state information
49 | // to restore the scene back to its current state.
50 | }
51 |
52 |
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // InspireDemo
4 | //
5 | // Created by xaoxuu on 2022/8/30.
6 | //
7 |
8 | import UIKit
9 | import Inspire
10 |
11 | class ViewController: UIViewController {
12 |
13 | @IBOutlet weak var title11: UILabel!
14 | @IBOutlet weak var title1: UILabel!
15 | @IBOutlet weak var title2: UILabel!
16 |
17 | @IBOutlet weak var title3: UILabel!
18 |
19 | @IBOutlet weak var headline: UILabel!
20 |
21 | @IBOutlet weak var subhead: UILabel!
22 |
23 | @IBOutlet weak var footnote: UILabel!
24 |
25 | @IBOutlet weak var body: UILabel!
26 |
27 | @IBOutlet weak var callout: UILabel!
28 |
29 | @IBOutlet weak var caption1: UILabel!
30 |
31 | @IBOutlet weak var caption2: UILabel!
32 |
33 | @IBOutlet weak var windowScene: UILabel!
34 |
35 | let mask = UIView()
36 |
37 | override func viewDidLoad() {
38 | super.viewDidLoad()
39 | // Do any additional setup after loading the view, typically from a nib.
40 |
41 | let v = UIView(frame: .init(x: 80, y: 100, width: 200, height: 100))
42 | v.backgroundColor = .red
43 | v.layer.cornerRadiusWithContinuous = 16
44 | view.addSubview(v)
45 |
46 | }
47 |
48 |
49 | override func touchesBegan(_ touches: Set, with event: UIEvent?) {
50 |
51 | let ipr = Inspire.current
52 |
53 | print("RootVC.safeAreaInsets: \(ipr.layout.safeAreaInsets(for: ipr.rootVC ?? self))")
54 | print("self.safeAreaInsets: \(Inspire.shared.layout.safeAreaInsets(for: self))")
55 |
56 | print("-----screen:")
57 | print("safeAreaInsets", ipr.screen.safeAreaInsets)
58 | print("bounds", ipr.screen.bounds)
59 | print("navBar", ipr.screen.navBar)
60 | print("statusBar", ipr.screen.statusBar)
61 | print("topBar", ipr.screen.topBar)
62 | print("tabBar", ipr.screen.tabBar)
63 | print("bottomBar", ipr.screen.bottomBar)
64 |
65 | print("-----")
66 | // print(ipr.)
67 |
68 | mask.backgroundColor = .init(white: 0.9, alpha: 1)
69 | let safeAreaInsets = Inspire.shared.screen.safeAreaInsets
70 | print(safeAreaInsets)
71 | mask.frame = .init(x: safeAreaInsets.left, y: safeAreaInsets.top, width: view.bounds.width - safeAreaInsets.left - safeAreaInsets.right, height: view.bounds.height - safeAreaInsets.top - safeAreaInsets.bottom)
72 | view.insertSubview(mask, at: 0)
73 |
74 |
75 | if #available(iOS 13.0, *) {
76 | windowScene.text = UIWindowScene.currentWindowScene?.description
77 | } else {
78 | // Fallback on earlier versions
79 | }
80 |
81 | }
82 |
83 | override func touchesMoved(_ touches: Set, with event: UIEvent?) {
84 | let vc = NewVC()
85 | vc.view.backgroundColor = .white
86 |
87 |
88 | present(vc, animated: true, completion: nil)
89 | }
90 |
91 |
92 | }
93 |
94 |
--------------------------------------------------------------------------------
/Sources/Inspire/InColor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ColorUtil.swift
3 | // Inspire
4 | //
5 | // Created by xaoxuu on 2019/3/26.
6 | // Copyright © 2019 xaoxuu.com. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 | // MARK: - 快速get
13 | public extension UIColor {
14 |
15 | /// 主题色
16 | static var theme: UIColor {
17 | return Inspire.current.color.theme
18 | }
19 |
20 | /// 强调色
21 | static var accent: UIColor {
22 | return Inspire.current.color.accent
23 | }
24 |
25 | /// 背景色
26 | static var background: UIColor {
27 | return Inspire.current.color.background
28 | }
29 |
30 | /// 成功
31 | static var success: UIColor {
32 | return Inspire.current.color.success
33 | }
34 |
35 | /// 警告
36 | static var warning: UIColor {
37 | return Inspire.current.color.warning
38 | }
39 |
40 | /// 失败
41 | static var failure: UIColor {
42 | return Inspire.current.color.failure
43 | }
44 |
45 | }
46 |
47 | // MARK: - 颜色工具
48 | public extension UIColor {
49 |
50 | /// 变深
51 | ///
52 | /// - Parameter ratio: 比例
53 | /// - Returns: 变深后的颜色
54 | func darken(_ ratio: CGFloat = 0.5) -> UIColor {
55 | var red = CGFloat(0)
56 | var green = CGFloat(0)
57 | var blue = CGFloat(0)
58 | var alpha = CGFloat(0)
59 | getRed(&red, green: &green, blue: &blue, alpha: &alpha)
60 | red = red * (1 - ratio)
61 | green = green * (1 - ratio)
62 | blue = blue * (1 - ratio)
63 | return UIColor(red: red, green: green, blue: blue, alpha: alpha)
64 | }
65 |
66 | /// 变浅
67 | ///
68 | /// - Parameter ratio: 比例
69 | /// - Returns: 变浅后的颜色
70 | func lighten(_ ratio: CGFloat = 0.5) -> UIColor {
71 | var red = CGFloat(0)
72 | var green = CGFloat(0)
73 | var blue = CGFloat(0)
74 | var alpha = CGFloat(0)
75 | getRed(&red, green: &green, blue: &blue, alpha: &alpha)
76 | red = red * (1 - ratio) + ratio
77 | green = green * (1 - ratio) + ratio
78 | blue = blue * (1 - ratio) + ratio
79 | return UIColor(red: red, green: green, blue: blue, alpha: alpha)
80 | }
81 |
82 | /// 当前颜色中的文字适合的颜色(参考)
83 | var forText: UIColor {
84 | func isLightColor() -> Bool {
85 | if self == UIColor.clear {
86 | return true
87 | }
88 | var red = CGFloat(0)
89 | var green = CGFloat(0)
90 | var blue = CGFloat(0)
91 | var alpha = CGFloat(0)
92 | self.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
93 | let grayLevel = red * 0.299 + green * 0.587 + blue * 0.114
94 | if grayLevel >= 192.0/255.0 {
95 | return true
96 | } else {
97 | return false
98 | }
99 | }
100 |
101 | if isLightColor() {
102 | return .darkText
103 | } else {
104 | return .white
105 | }
106 | }
107 |
108 |
109 | /// 根据hex字符串创建颜色
110 | ///
111 | /// - Parameter hex: hex字符串
112 | convenience init(_ hex: String) {
113 | func filter(hex: String) -> NSString{
114 | let set = NSCharacterSet.whitespacesAndNewlines
115 | var str = hex.trimmingCharacters(in: set).lowercased()
116 | if str.hasPrefix("#") {
117 | str = String(str.suffix(str.count-1))
118 | } else if str.hasPrefix("0x") {
119 | str = String(str.suffix(str.count-2))
120 | }
121 | return NSString(string: str)
122 | }
123 | let hex = filter(hex: hex)
124 | let length = hex.length
125 | guard length == 3 || length == 4 || length == 6 || length == 8 else {
126 | print("无效的hex")
127 | self.init("000")
128 | return
129 | }
130 | func floatValue(from hex: String) -> CGFloat {
131 | var result = Float(0)
132 | Scanner(string: "0x"+hex).scanHexFloat(&result)
133 | var maxStr = "0xf"
134 | if length > 5 {
135 | maxStr = "0xff"
136 | }
137 | var max = Float(0)
138 | Scanner(string: maxStr).scanHexFloat(&max)
139 | result = result / max
140 | return CGFloat(result)
141 | }
142 |
143 | func substring(of hex: NSString, loc: Int) -> String {
144 | if length == 3 || length == 4 {
145 | return hex.substring(with: NSRange.init(location: loc, length: 1))
146 | } else if length == 6 || length == 8 {
147 | return hex.substring(with: NSRange.init(location: 2*loc, length: 2))
148 | } else {
149 | return ""
150 | }
151 | }
152 |
153 | let r = floatValue(from: substring(of: hex, loc: 0))
154 | let g = floatValue(from: substring(of: hex, loc: 1))
155 | let b = floatValue(from: substring(of: hex, loc: 2))
156 | var a = CGFloat(1)
157 | if length == 4 || length == 8 {
158 | a = floatValue(from: substring(of: hex, loc: 3))
159 | }
160 | self.init(red: r, green: g, blue: b, alpha: a)
161 | }
162 |
163 | /// 生成当前颜色的hex字符串
164 | var hexString: String {
165 | func maxHexValue() -> CGFloat {
166 | var max = Float(0)
167 | Scanner(string: "0xff").scanHexFloat(&max)
168 | return CGFloat(max)
169 | }
170 | var r = CGFloat(0)
171 | var g = CGFloat(0)
172 | var b = CGFloat(0)
173 | var a = CGFloat(1)
174 | self.getRed(&r, green: &g, blue: &b, alpha: &a)
175 |
176 | let rr = String(format: "%02X", UInt32(r*maxHexValue()))
177 | let gg = String(format: "%02X", UInt32(g*maxHexValue()))
178 | let bb = String(format: "%02X", UInt32(b*maxHexValue()))
179 | let aa = String(format: "%02X", UInt32(a*maxHexValue()))
180 |
181 | return "#" + rr + gg + bb + aa
182 | }
183 | }
184 |
185 |
--------------------------------------------------------------------------------
/Sources/Inspire/Inspire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Inspire.swift
3 | // Inspire
4 | //
5 | // Created by xaoxuu on 2019/3/26.
6 | // Copyright © 2019 xaoxuu.com. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | internal let ipr = Inspire.shared
12 |
13 | public struct Inspire {
14 |
15 | /// 当前实例
16 | public static var shared = Inspire()
17 | /// 当前实例
18 | public static var current: Inspire {
19 | get {
20 | return shared
21 | }
22 | set {
23 | shared = newValue
24 | }
25 | }
26 |
27 | /// 颜色
28 | public struct InColor {
29 |
30 | /// 主题色
31 | public var theme = UIColor("#FF6868")
32 |
33 | /// 强调色
34 | public var accent = UIColor("#1BCBFA")
35 |
36 | /// 背景色
37 | public var background = UIColor("#EFEFEF")
38 |
39 | /// 成功的颜色
40 | public var success = UIColor("#34C749")
41 |
42 | /// 警告的颜色
43 | public var warning = UIColor("#FDBD41")
44 |
45 | /// 失败的颜色
46 | public var failure = UIColor("#F44336")
47 | }
48 |
49 | /// 字体
50 | public struct InFont {
51 |
52 | /// 字体
53 | ///
54 | /// - title: 标题部分字体名
55 | /// - body: 正文部分字体名
56 | /// - number: 数字部分字体名
57 | /// - code: 代码部分字体名
58 | public enum Scheme: String {
59 | case title = "title"
60 | case body = "body"
61 | case number = "number"
62 | case code = "code"
63 | }
64 |
65 | /// 标题部分字体名
66 | public var title = ""
67 | /// 正文部分字体名
68 | public var body = ""
69 | /// 数字部分字体名
70 | public var number = ""
71 | /// 代码部分字体名
72 | public var code = ""
73 |
74 | /// 字号缩放倍数
75 | public var scale = CGFloat(1)
76 |
77 | }
78 |
79 | /// 布局
80 | public struct InLayout {
81 |
82 | /// 圆角
83 | public struct CornerRadius {
84 | public var large = CGFloat(16)
85 | public var medium = CGFloat(12)
86 | public var regular = CGFloat(8)
87 | public var small = CGFloat(4)
88 | }
89 |
90 | /// 填充
91 | public var padding = CGFloat(8)
92 |
93 | /// 余量
94 | public var margin = CGFloat(16)
95 |
96 | /// 圆角
97 | public var cornerRadius = CornerRadius()
98 |
99 | /// 行高
100 | public var rowHeight = CGFloat(50)
101 |
102 | /// 屏幕
103 | public struct InScreen {}
104 |
105 | }
106 |
107 |
108 | /// 颜色
109 | public var color = InColor()
110 |
111 | /// 字体
112 | public var font = InFont()
113 |
114 | /// 布局
115 | public var layout = InLayout()
116 |
117 | /// 常量
118 | public var screen = InLayout.InScreen()
119 |
120 | private static var currentRootVC: UIViewController?
121 | /// 默认可以自动获取,如果获取失败请手动设置
122 | public var rootVC: UIViewController? {
123 | get {
124 | if let vc = Inspire.currentRootVC {
125 | return vc
126 | } else {
127 | // 尝试获取RootVC
128 | var windows: [UIWindow]
129 | if #available(iOS 13.0, *) {
130 | windows = windowScene?.windows ?? []
131 | } else {
132 | windows = UIApplication.shared.windows
133 | }
134 | let ws = windows.filter { (w) -> Bool in
135 | // 去除掉诸如 UITextEffectsWindow 这样的类,去掉隐藏的Window
136 | if "\(type(of:w))" == "UIWindow" && w.isHidden == false && w.windowLevel == .normal {
137 | return true
138 | } else {
139 | return false
140 | }
141 | }
142 | for w in ws {
143 | if let vc = w.rootViewController {
144 | Inspire.currentRootVC = vc
145 | return vc
146 | }
147 | }
148 | print("⚠️自动获取根控制器失败,请手动设置根控制器")
149 | return nil
150 | }
151 | }
152 | set {
153 | Inspire.currentRootVC = newValue
154 | }
155 | }
156 |
157 | /// 默认可以自动获取,如果获取失败请手动设置
158 | @available(iOS 13.0, *)
159 | private static var currentWindowScene: UIWindowScene?
160 |
161 | /// 默认可以自动获取,如果获取失败请手动设置
162 | @available(iOS 13.0, *)
163 | public var windowScene: UIWindowScene? {
164 | get {
165 | if let scene = Inspire.currentWindowScene {
166 | return scene
167 | } else {
168 | return UIWindowScene.currentWindowScene
169 | }
170 | }
171 | set {
172 | Inspire.currentWindowScene = newValue
173 | }
174 | }
175 |
176 | /// 创建默认实例
177 | public init() {
178 |
179 | }
180 |
181 |
182 | }
183 |
184 |
185 | // MARK: - 多主题
186 | extension Inspire {
187 |
188 | /// 根据字典来创建主题模型
189 | ///
190 | /// - Parameter dictionary: 字典
191 | public init(_ dictionary: [String: Any]) {
192 | if let dict = dictionary["color"] as? [String: String] {
193 | color.theme = UIColor(dict["theme"] ?? "#FF6868")
194 | color.accent = UIColor(dict["accent"] ?? "#1BCBFA")
195 | color.background = UIColor(dict["background"] ?? "#EFEFEF")
196 | color.success = UIColor(dict["success"] ?? "#34C749")
197 | color.warning = UIColor(dict["warning"] ?? "#FDBD41")
198 | color.failure = UIColor(dict["failure"] ?? "#F44336")
199 | }
200 | if let dict = dictionary["font"] as? [String: String] {
201 | font.title = dict["title"] ?? ""
202 | font.body = dict["body"] ?? ""
203 | font.number = dict["number"] ?? ""
204 | font.code = dict["code"] ?? ""
205 | if let str = dict["scale"] {
206 | if let d = Double(str) {
207 | font.scale = CGFloat(d)
208 | }
209 | }
210 | }
211 | if let dict = dictionary["layout"] as? [String: Any] {
212 | if let str = dict["padding"] as? String {
213 | if let d = Double(str) {
214 | layout.padding = CGFloat(d)
215 | }
216 | }
217 | if let str = dict["margin"] as? String {
218 | if let d = Double(str) {
219 | layout.margin = CGFloat(d)
220 | }
221 | }
222 | if let str = dict["rowHeight"] as? String {
223 | if let d = Double(str) {
224 | layout.rowHeight = CGFloat(d)
225 | }
226 | }
227 | if let dict2 = dict["cornerRadius"] as? [String: String] {
228 | if let str = dict2["large"] {
229 | if let d = Double(str) {
230 | layout.cornerRadius.large = CGFloat(d)
231 | }
232 | }
233 | if let str = dict2["medium"] {
234 | if let d = Double(str) {
235 | layout.cornerRadius.medium = CGFloat(d)
236 | }
237 | }
238 | if let str = dict2["regular"] {
239 | if let d = Double(str) {
240 | layout.cornerRadius.regular = CGFloat(d)
241 | }
242 | }
243 | if let str = dict2["small"] {
244 | if let d = Double(str) {
245 | layout.cornerRadius.small = CGFloat(d)
246 | }
247 | }
248 | }
249 |
250 | }
251 | }
252 |
253 | /// 应用主题
254 | ///
255 | /// - Parameter ins: 主题模型
256 | public static func apply(_ ins: Inspire) {
257 | shared = ins
258 | NotificationCenter.default.post(name: Inspire.Event.didUpdate, object: ins)
259 | }
260 |
261 | /// 导出主题
262 | ///
263 | /// - Returns: 字典
264 | public func export() -> [String: [String: Any]] {
265 | var result = [String: [String: Any]]()
266 | let fontDict = [InFont.Scheme.title.rawValue: font.title,
267 | InFont.Scheme.body.rawValue: font.body,
268 | InFont.Scheme.number.rawValue: font.number,
269 | InFont.Scheme.code.rawValue: font.code,
270 | "scale": String(Double(font.scale))]
271 | let colorDict = ["theme": color.theme.hexString,
272 | "accent": color.accent.hexString,
273 | "background": color.background.hexString,
274 | "success": color.success.hexString,
275 | "warning": color.warning.hexString,
276 | "failure": color.failure.hexString]
277 | var layoutDict = [String: Any]()
278 | layoutDict["padding"] = String(Double(layout.padding))
279 | layoutDict["margin"] = String(Double(layout.margin))
280 | layoutDict["rowHeight"] = String(Double(layout.rowHeight))
281 | let cornerRadiusDict = ["large": String(Double(layout.cornerRadius.large)),
282 | "medium": String(Double(layout.cornerRadius.medium)),
283 | "regular": String(Double(layout.cornerRadius.regular)),
284 | "small": String(Double(layout.cornerRadius.small))]
285 | layoutDict["cornerRadius"] = cornerRadiusDict
286 | result["font"] = fontDict
287 | result["color"] = colorDict
288 | result["layout"] = layoutDict
289 | return result
290 | }
291 |
292 | }
293 |
294 | public extension Inspire {
295 | struct Event {
296 | public static let didUpdate = Notification.Name.init(rawValue: "Inspire.didUpdate")
297 | }
298 |
299 |
300 | }
301 |
302 |
--------------------------------------------------------------------------------
/Sources/Inspire/InLayout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LayoutUtil.swift
3 | // Inspire
4 | //
5 | // Created by xaoxuu on 2019/3/26.
6 | // Copyright © 2019 xaoxuu.com. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // MARK: - 设备布局常量
12 | public extension Inspire.InLayout {
13 |
14 | /// 设备常量
15 | struct InDevice {
16 |
17 | /// 屏幕尺寸
18 | public enum ScreenSize: Int {
19 | case unknown
20 | case iPhone_Legacy_3_5
21 | case iPhone_Legacy_4_0
22 | case iPhone_Legacy_4_7
23 | case iPhone_Legacy_5_5
24 | case iPhone_New_5_8 // iPhone X
25 | case iPhone_New_6_1 // iPhone XR | 11
26 | case iPhone_New_6_5 // iPhone XS Max、11 Pro Max
27 | case iPhone_New_5_4 // iPhone 12 mini | 13 mini
28 | case iPhone_New_6_1_G2 // iPhone 12、12 Pro、13、13 Pro、14
29 | case iPhone_New_6_7 // 12 Pro Max、13 Pro Max、14 Plus
30 | case iPhone_New_6_1_G3 // 14 Pro
31 | case iPhone_New_6_7_G2 // 14 Pro Max
32 | case iPad_Legacy_7_9
33 | case iPad_Legacy_9_7
34 | case iPad_Legacy_10_2
35 | case iPad_Legacy_10_5
36 | case iPad_New_7_9 // mini 6
37 | case iPad_New_10_9 // Air 5
38 | case iPad_New_11 // iPad Pro 11
39 | case iPad_New_12_9 // iPad Pro 12.9
40 |
41 | /// 是否是全面屏手机
42 | public var isNewPhone: Bool {
43 | if UIDevice.current.userInterfaceIdiom == .phone {
44 | let ss = Inspire.InLayout.InDevice.screenSize
45 | if ss == .iPhone_Legacy_3_5 || ss == .iPhone_Legacy_4_0 || ss == .iPhone_Legacy_4_7 || ss == .iPhone_Legacy_5_5 {
46 | return false
47 | } else {
48 | // 新推出的新尺寸的全面屏iPhone
49 | return true
50 | }
51 | }
52 | return false
53 | }
54 | /// 是否是全面屏iPad
55 | public var isNewPad: Bool {
56 | if UIDevice.current.userInterfaceIdiom == .pad {
57 | let ss = Inspire.InLayout.InDevice.screenSize
58 | if ss == .iPad_Legacy_7_9 || ss == .iPad_Legacy_9_7 || ss == .iPad_Legacy_10_5 || ss == .iPad_New_12_9 {
59 | return false
60 | } else {
61 | // 新推出的新尺寸的全面屏iPad
62 | return true
63 | }
64 | }
65 | return false
66 | }
67 | }
68 |
69 | /// 屏幕尺寸
70 | public static let screenSize: ScreenSize = {
71 | if UIDevice.current.userInterfaceIdiom == .pad {
72 | // FIXME: 适配iPad
73 | if let s = UIScreen.main.currentMode?.size {
74 | switch s {
75 | case CGSize(width: 1536, height: 2048):
76 | return ScreenSize.iPad_Legacy_7_9
77 | case CGSize(width: 1536, height: 2048):
78 | return ScreenSize.iPad_Legacy_9_7
79 | case CGSize(width: 1620, height: 2160):
80 | return ScreenSize.iPad_Legacy_10_2
81 | case CGSize(width: 1668, height: 2224):
82 | return ScreenSize.iPad_Legacy_10_5
83 | case CGSize(width: 1488, height: 2266):
84 | return ScreenSize.iPad_New_7_9
85 | case CGSize(width: 1640, height: 2360):
86 | return ScreenSize.iPad_New_10_9
87 | case CGSize(width: 1668, height: 2388):
88 | return ScreenSize.iPad_New_11
89 | case CGSize(width: 2048, height: 2732):
90 | return ScreenSize.iPad_New_12_9
91 | default:
92 | break
93 | }
94 | }
95 | // 尚未兼容的新尺寸的iPad默认被认为是11寸
96 | return ScreenSize.iPad_New_11
97 | } else if UIDevice.current.userInterfaceIdiom == .phone {
98 | if let s = UIScreen.main.currentMode?.size {
99 | switch s {
100 | case CGSize(width: 320, height: 480), CGSize(width: 640, height: 960):
101 | return ScreenSize.iPhone_Legacy_3_5
102 | case CGSize(width: 640, height: 1136):
103 | return ScreenSize.iPhone_Legacy_4_0
104 | case CGSize(width: 750, height: 1334):
105 | return ScreenSize.iPhone_Legacy_4_7
106 | case CGSize(width: 1242, height: 2208):
107 | return ScreenSize.iPhone_Legacy_5_5
108 | case CGSize(width: 1125, height: 2436):
109 | return ScreenSize.iPhone_New_5_8
110 | case CGSize(width: 828, height: 1792):
111 | return ScreenSize.iPhone_New_6_1
112 | case CGSize(width: 1242, height: 2688):
113 | return ScreenSize.iPhone_New_6_5
114 | case CGSize(width: 1080, height: 2340):
115 | return ScreenSize.iPhone_New_5_4
116 | case CGSize(width: 1170, height: 2532):
117 | return ScreenSize.iPhone_New_6_1_G2
118 | case CGSize(width: 1284, height: 2778):
119 | return ScreenSize.iPhone_New_6_7
120 | case CGSize(width: 1179, height: 2556):
121 | return ScreenSize.iPhone_New_6_1_G3
122 | case CGSize(width: 1290, height: 2796):
123 | return ScreenSize.iPhone_New_6_7_G2
124 | default:
125 | break
126 | }
127 | } else {
128 | // 尚未兼容的新尺寸的iPhone默认被认为是6.1寸
129 | return ScreenSize.iPhone_New_6_1_G2
130 | }
131 | }
132 | // 暂不支持 iPhone、iPad 以外的设备
133 | return ScreenSize.unknown
134 | }()
135 |
136 | /// 获取当前状态栏高度
137 | public static var statusBarWindowHeight: CGFloat {
138 | if #available(iOS 13.0, *) {
139 | return ipr.windowScene?.statusBarManager?.statusBarFrame.height ?? .zero
140 | } else {
141 | return UIApplication.shared.statusBarFrame.size.height
142 | }
143 | }
144 |
145 |
146 | /// 竖屏时底部的安全区域高度
147 | public static let bottomSafeAreaHeightOnPortrait: CGFloat = {
148 | if screenSize.isNewPhone {
149 | return 34
150 | } else if screenSize == .iPad_New_11 {
151 | return 21
152 | }
153 | return 0
154 | }()
155 |
156 | /// 横屏时底部的安全区域高度
157 | public static let bottomSafeAreaHeightOnLandscape: CGFloat = {
158 | if screenSize.isNewPhone || screenSize.isNewPad {
159 | return 21
160 | }
161 | return 0
162 | }()
163 |
164 | }
165 |
166 | /// 获取某个视图控制器的布局安全距离
167 | /// - Parameter viewController: 视图控制器
168 | func safeAreaInsets(for viewController: UIViewController) -> UIEdgeInsets {
169 | if #available(iOS 11.0, *) {
170 | return viewController.view.safeAreaInsets
171 | } else {
172 | // Fallback on earlier versions
173 | return Inspire.shared.screen.safeAreaInsets
174 | }
175 | }
176 |
177 | /// 获取某个视图控制器的顶部栏(状态栏+导航栏)的高度
178 | /// - Parameter viewController: 视图控制器
179 | func topBarHeight(for viewController: UIViewController?) -> CGFloat {
180 | if let nav = viewController as? UINavigationController {
181 | var h = nav.navigationBar.frame.size.height
182 | h += safeAreaInsets(for: nav).top
183 | return h
184 | } else if let vc = viewController {
185 | return safeAreaInsets(for: vc).top + (vc.navigationController?.navigationBar.frame.size.height ?? Inspire.shared.screen.navBar.height)
186 | } else {
187 | return 0
188 | }
189 | }
190 |
191 | /// 获取某个视图控制器的底部栏(Tabbar和底部安全区域)高度
192 | /// - Parameter viewController: 视图控制器
193 | func bottomBarHeight(for viewController: UIViewController) -> CGFloat {
194 | return safeAreaInsets(for: viewController).bottom + (viewController.tabBarController?.tabBar.frame.height ?? Inspire.shared.screen.tabBar.height)
195 | }
196 |
197 | }
198 |
199 | public extension Inspire {
200 | typealias InScreen = Inspire.InLayout.InScreen
201 | typealias InDevice = Inspire.InLayout.InDevice
202 | }
203 |
204 |
205 | // MARK: - 窗口布局尺寸常量
206 | public extension Inspire.InLayout.InScreen {
207 |
208 | var bounds: CGRect {
209 | return UIScreen.main.bounds
210 | }
211 | var size: CGSize {
212 | return UIScreen.main.bounds.size
213 | }
214 | var width: CGFloat {
215 | return UIScreen.main.bounds.size.width
216 | }
217 | var height: CGFloat {
218 | return UIScreen.main.bounds.size.height
219 | }
220 |
221 | /// 根控制器的屏幕布局安全区域
222 | var safeAreaInsets: UIEdgeInsets {
223 | if #available(iOS 11.0, *) {
224 | if let rootVC = Inspire.shared.rootVC {
225 | return rootVC.view.safeAreaInsets
226 | } else {
227 | // 拿不到根控制器,在 Inspire.shared.rootVC 里已经抛出了警告
228 | return .zero
229 | }
230 | } else {
231 | // iOS 11 以下的版本不存在 safeAreaInsets
232 | return .zero
233 | }
234 | }
235 |
236 | /// 状态栏尺寸
237 | var statusBar: CGSize {
238 | return CGSize.init(width: width, height: safeAreaInsets.top)
239 | }
240 |
241 | /// 导航栏尺寸(不含状态栏)
242 | var navBar: CGSize {
243 | return CGSize.init(width: width, height: 44)
244 | }
245 |
246 | /// 状态栏+导航栏区域尺寸
247 | var topBar: CGSize {
248 | return CGSize.init(width: width, height: safeAreaInsets.top + navBar.height)
249 | }
250 |
251 | /// TabBar尺寸
252 | var tabBar: CGSize {
253 | return CGSize.init(width: width, height: 49)
254 | }
255 |
256 | /// TabBar+底部安全区域尺寸
257 | var bottomBar: CGSize {
258 | return CGSize.init(width: width, height: safeAreaInsets.bottom + tabBar.height)
259 | }
260 |
261 |
262 | }
263 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
28 |
34 |
40 |
46 |
52 |
58 |
64 |
70 |
76 |
82 |
83 |
84 |
90 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/InspireDemo/InspireDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 55;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | CD01708928BE506C00E894F6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01708828BE506C00E894F6 /* AppDelegate.swift */; };
11 | CD01708B28BE506C00E894F6 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01708A28BE506C00E894F6 /* SceneDelegate.swift */; };
12 | CD01708D28BE506C00E894F6 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01708C28BE506C00E894F6 /* ViewController.swift */; };
13 | CD01709028BE506C00E894F6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CD01708E28BE506C00E894F6 /* Main.storyboard */; };
14 | CD01709228BE506D00E894F6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD01709128BE506D00E894F6 /* Assets.xcassets */; };
15 | CD01709528BE506D00E894F6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CD01709328BE506D00E894F6 /* LaunchScreen.storyboard */; };
16 | CD01709F28BE515900E894F6 /* NewVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01709E28BE515900E894F6 /* NewVC.swift */; };
17 | CD0170A128BE516800E894F6 /* MyInspire.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD0170A028BE516800E894F6 /* MyInspire.swift */; };
18 | CD0170A328BE518C00E894F6 /* theme.json in Resources */ = {isa = PBXBuildFile; fileRef = CD0170A228BE518C00E894F6 /* theme.json */; };
19 | CD0170A628BE51E100E894F6 /* Inspire in Frameworks */ = {isa = PBXBuildFile; productRef = CD0170A528BE51E100E894F6 /* Inspire */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXFileReference section */
23 | CD01708528BE506C00E894F6 /* InspireDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = InspireDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
24 | CD01708828BE506C00E894F6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
25 | CD01708A28BE506C00E894F6 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
26 | CD01708C28BE506C00E894F6 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
27 | CD01708F28BE506C00E894F6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
28 | CD01709128BE506D00E894F6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
29 | CD01709428BE506D00E894F6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
30 | CD01709628BE506D00E894F6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
31 | CD01709D28BE50AA00E894F6 /* Inspire */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Inspire; path = ..; sourceTree = ""; };
32 | CD01709E28BE515900E894F6 /* NewVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewVC.swift; sourceTree = ""; };
33 | CD0170A028BE516800E894F6 /* MyInspire.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInspire.swift; sourceTree = ""; };
34 | CD0170A228BE518C00E894F6 /* theme.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = theme.json; sourceTree = ""; };
35 | /* End PBXFileReference section */
36 |
37 | /* Begin PBXFrameworksBuildPhase section */
38 | CD01708228BE506C00E894F6 /* Frameworks */ = {
39 | isa = PBXFrameworksBuildPhase;
40 | buildActionMask = 2147483647;
41 | files = (
42 | CD0170A628BE51E100E894F6 /* Inspire in Frameworks */,
43 | );
44 | runOnlyForDeploymentPostprocessing = 0;
45 | };
46 | /* End PBXFrameworksBuildPhase section */
47 |
48 | /* Begin PBXGroup section */
49 | CD01707C28BE506C00E894F6 = {
50 | isa = PBXGroup;
51 | children = (
52 | CD01709C28BE50AA00E894F6 /* Packages */,
53 | CD01708728BE506C00E894F6 /* InspireDemo */,
54 | CD01708628BE506C00E894F6 /* Products */,
55 | CD0170A428BE51E100E894F6 /* Frameworks */,
56 | );
57 | sourceTree = "";
58 | };
59 | CD01708628BE506C00E894F6 /* Products */ = {
60 | isa = PBXGroup;
61 | children = (
62 | CD01708528BE506C00E894F6 /* InspireDemo.app */,
63 | );
64 | name = Products;
65 | sourceTree = "";
66 | };
67 | CD01708728BE506C00E894F6 /* InspireDemo */ = {
68 | isa = PBXGroup;
69 | children = (
70 | CD01708828BE506C00E894F6 /* AppDelegate.swift */,
71 | CD01708A28BE506C00E894F6 /* SceneDelegate.swift */,
72 | CD01708C28BE506C00E894F6 /* ViewController.swift */,
73 | CD01709E28BE515900E894F6 /* NewVC.swift */,
74 | CD0170A028BE516800E894F6 /* MyInspire.swift */,
75 | CD0170A228BE518C00E894F6 /* theme.json */,
76 | CD01708E28BE506C00E894F6 /* Main.storyboard */,
77 | CD01709128BE506D00E894F6 /* Assets.xcassets */,
78 | CD01709328BE506D00E894F6 /* LaunchScreen.storyboard */,
79 | CD01709628BE506D00E894F6 /* Info.plist */,
80 | );
81 | path = InspireDemo;
82 | sourceTree = "";
83 | };
84 | CD01709C28BE50AA00E894F6 /* Packages */ = {
85 | isa = PBXGroup;
86 | children = (
87 | CD01709D28BE50AA00E894F6 /* Inspire */,
88 | );
89 | name = Packages;
90 | sourceTree = "";
91 | };
92 | CD0170A428BE51E100E894F6 /* Frameworks */ = {
93 | isa = PBXGroup;
94 | children = (
95 | );
96 | name = Frameworks;
97 | sourceTree = "";
98 | };
99 | /* End PBXGroup section */
100 |
101 | /* Begin PBXNativeTarget section */
102 | CD01708428BE506C00E894F6 /* InspireDemo */ = {
103 | isa = PBXNativeTarget;
104 | buildConfigurationList = CD01709928BE506D00E894F6 /* Build configuration list for PBXNativeTarget "InspireDemo" */;
105 | buildPhases = (
106 | CD01708128BE506C00E894F6 /* Sources */,
107 | CD01708228BE506C00E894F6 /* Frameworks */,
108 | CD01708328BE506C00E894F6 /* Resources */,
109 | );
110 | buildRules = (
111 | );
112 | dependencies = (
113 | );
114 | name = InspireDemo;
115 | packageProductDependencies = (
116 | CD0170A528BE51E100E894F6 /* Inspire */,
117 | );
118 | productName = InspireDemo;
119 | productReference = CD01708528BE506C00E894F6 /* InspireDemo.app */;
120 | productType = "com.apple.product-type.application";
121 | };
122 | /* End PBXNativeTarget section */
123 |
124 | /* Begin PBXProject section */
125 | CD01707D28BE506C00E894F6 /* Project object */ = {
126 | isa = PBXProject;
127 | attributes = {
128 | BuildIndependentTargetsInParallel = 1;
129 | LastSwiftUpdateCheck = 1340;
130 | LastUpgradeCheck = 1340;
131 | TargetAttributes = {
132 | CD01708428BE506C00E894F6 = {
133 | CreatedOnToolsVersion = 13.4.1;
134 | };
135 | };
136 | };
137 | buildConfigurationList = CD01708028BE506C00E894F6 /* Build configuration list for PBXProject "InspireDemo" */;
138 | compatibilityVersion = "Xcode 13.0";
139 | developmentRegion = en;
140 | hasScannedForEncodings = 0;
141 | knownRegions = (
142 | en,
143 | Base,
144 | );
145 | mainGroup = CD01707C28BE506C00E894F6;
146 | productRefGroup = CD01708628BE506C00E894F6 /* Products */;
147 | projectDirPath = "";
148 | projectRoot = "";
149 | targets = (
150 | CD01708428BE506C00E894F6 /* InspireDemo */,
151 | );
152 | };
153 | /* End PBXProject section */
154 |
155 | /* Begin PBXResourcesBuildPhase section */
156 | CD01708328BE506C00E894F6 /* Resources */ = {
157 | isa = PBXResourcesBuildPhase;
158 | buildActionMask = 2147483647;
159 | files = (
160 | CD01709528BE506D00E894F6 /* LaunchScreen.storyboard in Resources */,
161 | CD0170A328BE518C00E894F6 /* theme.json in Resources */,
162 | CD01709228BE506D00E894F6 /* Assets.xcassets in Resources */,
163 | CD01709028BE506C00E894F6 /* Main.storyboard in Resources */,
164 | );
165 | runOnlyForDeploymentPostprocessing = 0;
166 | };
167 | /* End PBXResourcesBuildPhase section */
168 |
169 | /* Begin PBXSourcesBuildPhase section */
170 | CD01708128BE506C00E894F6 /* Sources */ = {
171 | isa = PBXSourcesBuildPhase;
172 | buildActionMask = 2147483647;
173 | files = (
174 | CD01708D28BE506C00E894F6 /* ViewController.swift in Sources */,
175 | CD01709F28BE515900E894F6 /* NewVC.swift in Sources */,
176 | CD0170A128BE516800E894F6 /* MyInspire.swift in Sources */,
177 | CD01708928BE506C00E894F6 /* AppDelegate.swift in Sources */,
178 | CD01708B28BE506C00E894F6 /* SceneDelegate.swift in Sources */,
179 | );
180 | runOnlyForDeploymentPostprocessing = 0;
181 | };
182 | /* End PBXSourcesBuildPhase section */
183 |
184 | /* Begin PBXVariantGroup section */
185 | CD01708E28BE506C00E894F6 /* Main.storyboard */ = {
186 | isa = PBXVariantGroup;
187 | children = (
188 | CD01708F28BE506C00E894F6 /* Base */,
189 | );
190 | name = Main.storyboard;
191 | sourceTree = "";
192 | };
193 | CD01709328BE506D00E894F6 /* LaunchScreen.storyboard */ = {
194 | isa = PBXVariantGroup;
195 | children = (
196 | CD01709428BE506D00E894F6 /* Base */,
197 | );
198 | name = LaunchScreen.storyboard;
199 | sourceTree = "";
200 | };
201 | /* End PBXVariantGroup section */
202 |
203 | /* Begin XCBuildConfiguration section */
204 | CD01709728BE506D00E894F6 /* Debug */ = {
205 | isa = XCBuildConfiguration;
206 | buildSettings = {
207 | ALWAYS_SEARCH_USER_PATHS = NO;
208 | CLANG_ANALYZER_NONNULL = YES;
209 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
210 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
211 | CLANG_ENABLE_MODULES = YES;
212 | CLANG_ENABLE_OBJC_ARC = YES;
213 | CLANG_ENABLE_OBJC_WEAK = YES;
214 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
215 | CLANG_WARN_BOOL_CONVERSION = YES;
216 | CLANG_WARN_COMMA = YES;
217 | CLANG_WARN_CONSTANT_CONVERSION = YES;
218 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
219 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
220 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
221 | CLANG_WARN_EMPTY_BODY = YES;
222 | CLANG_WARN_ENUM_CONVERSION = YES;
223 | CLANG_WARN_INFINITE_RECURSION = YES;
224 | CLANG_WARN_INT_CONVERSION = YES;
225 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
226 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
227 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
228 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
229 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
230 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
231 | CLANG_WARN_STRICT_PROTOTYPES = YES;
232 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
233 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
234 | CLANG_WARN_UNREACHABLE_CODE = YES;
235 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
236 | COPY_PHASE_STRIP = NO;
237 | DEBUG_INFORMATION_FORMAT = dwarf;
238 | ENABLE_STRICT_OBJC_MSGSEND = YES;
239 | ENABLE_TESTABILITY = YES;
240 | GCC_C_LANGUAGE_STANDARD = gnu11;
241 | GCC_DYNAMIC_NO_PIC = NO;
242 | GCC_NO_COMMON_BLOCKS = YES;
243 | GCC_OPTIMIZATION_LEVEL = 0;
244 | GCC_PREPROCESSOR_DEFINITIONS = (
245 | "DEBUG=1",
246 | "$(inherited)",
247 | );
248 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
249 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
250 | GCC_WARN_UNDECLARED_SELECTOR = YES;
251 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
252 | GCC_WARN_UNUSED_FUNCTION = YES;
253 | GCC_WARN_UNUSED_VARIABLE = YES;
254 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
255 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
256 | MTL_FAST_MATH = YES;
257 | ONLY_ACTIVE_ARCH = YES;
258 | SDKROOT = iphoneos;
259 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
260 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
261 | };
262 | name = Debug;
263 | };
264 | CD01709828BE506D00E894F6 /* Release */ = {
265 | isa = XCBuildConfiguration;
266 | buildSettings = {
267 | ALWAYS_SEARCH_USER_PATHS = NO;
268 | CLANG_ANALYZER_NONNULL = YES;
269 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
271 | CLANG_ENABLE_MODULES = YES;
272 | CLANG_ENABLE_OBJC_ARC = YES;
273 | CLANG_ENABLE_OBJC_WEAK = YES;
274 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
275 | CLANG_WARN_BOOL_CONVERSION = YES;
276 | CLANG_WARN_COMMA = YES;
277 | CLANG_WARN_CONSTANT_CONVERSION = YES;
278 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
279 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
280 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
281 | CLANG_WARN_EMPTY_BODY = YES;
282 | CLANG_WARN_ENUM_CONVERSION = YES;
283 | CLANG_WARN_INFINITE_RECURSION = YES;
284 | CLANG_WARN_INT_CONVERSION = YES;
285 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
286 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
287 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
288 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
289 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
290 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
291 | CLANG_WARN_STRICT_PROTOTYPES = YES;
292 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
293 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
294 | CLANG_WARN_UNREACHABLE_CODE = YES;
295 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
296 | COPY_PHASE_STRIP = NO;
297 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
298 | ENABLE_NS_ASSERTIONS = NO;
299 | ENABLE_STRICT_OBJC_MSGSEND = YES;
300 | GCC_C_LANGUAGE_STANDARD = gnu11;
301 | GCC_NO_COMMON_BLOCKS = YES;
302 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
303 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
304 | GCC_WARN_UNDECLARED_SELECTOR = YES;
305 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
306 | GCC_WARN_UNUSED_FUNCTION = YES;
307 | GCC_WARN_UNUSED_VARIABLE = YES;
308 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
309 | MTL_ENABLE_DEBUG_INFO = NO;
310 | MTL_FAST_MATH = YES;
311 | SDKROOT = iphoneos;
312 | SWIFT_COMPILATION_MODE = wholemodule;
313 | SWIFT_OPTIMIZATION_LEVEL = "-O";
314 | VALIDATE_PRODUCT = YES;
315 | };
316 | name = Release;
317 | };
318 | CD01709A28BE506D00E894F6 /* Debug */ = {
319 | isa = XCBuildConfiguration;
320 | buildSettings = {
321 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
322 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
323 | CODE_SIGN_STYLE = Automatic;
324 | CURRENT_PROJECT_VERSION = 1;
325 | DEVELOPMENT_TEAM = DASH6JFSDW;
326 | GENERATE_INFOPLIST_FILE = YES;
327 | INFOPLIST_FILE = InspireDemo/Info.plist;
328 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
329 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
330 | INFOPLIST_KEY_UIMainStoryboardFile = Main;
331 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
332 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
333 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
334 | LD_RUNPATH_SEARCH_PATHS = (
335 | "$(inherited)",
336 | "@executable_path/Frameworks",
337 | );
338 | MARKETING_VERSION = 1.0;
339 | PRODUCT_BUNDLE_IDENTIFIER = com.xaoxuu.InspireDemo;
340 | PRODUCT_NAME = "$(TARGET_NAME)";
341 | SWIFT_EMIT_LOC_STRINGS = YES;
342 | SWIFT_VERSION = 5.0;
343 | TARGETED_DEVICE_FAMILY = "1,2";
344 | };
345 | name = Debug;
346 | };
347 | CD01709B28BE506D00E894F6 /* Release */ = {
348 | isa = XCBuildConfiguration;
349 | buildSettings = {
350 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
351 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
352 | CODE_SIGN_STYLE = Automatic;
353 | CURRENT_PROJECT_VERSION = 1;
354 | DEVELOPMENT_TEAM = DASH6JFSDW;
355 | GENERATE_INFOPLIST_FILE = YES;
356 | INFOPLIST_FILE = InspireDemo/Info.plist;
357 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
358 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
359 | INFOPLIST_KEY_UIMainStoryboardFile = Main;
360 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
361 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
362 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
363 | LD_RUNPATH_SEARCH_PATHS = (
364 | "$(inherited)",
365 | "@executable_path/Frameworks",
366 | );
367 | MARKETING_VERSION = 1.0;
368 | PRODUCT_BUNDLE_IDENTIFIER = com.xaoxuu.InspireDemo;
369 | PRODUCT_NAME = "$(TARGET_NAME)";
370 | SWIFT_EMIT_LOC_STRINGS = YES;
371 | SWIFT_VERSION = 5.0;
372 | TARGETED_DEVICE_FAMILY = "1,2";
373 | };
374 | name = Release;
375 | };
376 | /* End XCBuildConfiguration section */
377 |
378 | /* Begin XCConfigurationList section */
379 | CD01708028BE506C00E894F6 /* Build configuration list for PBXProject "InspireDemo" */ = {
380 | isa = XCConfigurationList;
381 | buildConfigurations = (
382 | CD01709728BE506D00E894F6 /* Debug */,
383 | CD01709828BE506D00E894F6 /* Release */,
384 | );
385 | defaultConfigurationIsVisible = 0;
386 | defaultConfigurationName = Release;
387 | };
388 | CD01709928BE506D00E894F6 /* Build configuration list for PBXNativeTarget "InspireDemo" */ = {
389 | isa = XCConfigurationList;
390 | buildConfigurations = (
391 | CD01709A28BE506D00E894F6 /* Debug */,
392 | CD01709B28BE506D00E894F6 /* Release */,
393 | );
394 | defaultConfigurationIsVisible = 0;
395 | defaultConfigurationName = Release;
396 | };
397 | /* End XCConfigurationList section */
398 |
399 | /* Begin XCSwiftPackageProductDependency section */
400 | CD0170A528BE51E100E894F6 /* Inspire */ = {
401 | isa = XCSwiftPackageProductDependency;
402 | productName = Inspire;
403 | };
404 | /* End XCSwiftPackageProductDependency section */
405 | };
406 | rootObject = CD01707D28BE506C00E894F6 /* Project object */;
407 | }
408 |
--------------------------------------------------------------------------------