Commit e8292061 ilCode

init project

1 个父辈 fc6d3474
正在显示 76 个修改的文件 包含 4168 行增加164 行删除
......@@ -6,15 +6,22 @@
objectVersion = 77;
objects = {
/* Begin PBXBuildFile section */
8CE25481ABBABE93555912FC /* Pods_NumberCube.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34EB55E037AD4972285400AD /* Pods_NumberCube.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
0BF0289D9C625E25AC92A4B5 /* Pods-NumberCube.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NumberCube.debug.xcconfig"; path = "Target Support Files/Pods-NumberCube/Pods-NumberCube.debug.xcconfig"; sourceTree = "<group>"; };
34EB55E037AD4972285400AD /* Pods_NumberCube.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NumberCube.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5E2024082D94D6E4005C4682 /* NumberCube.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NumberCube.app; sourceTree = BUILT_PRODUCTS_DIR; };
72041B39D629EC7D4060B7DE /* Pods-NumberCube.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NumberCube.release.xcconfig"; path = "Target Support Files/Pods-NumberCube/Pods-NumberCube.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
5E20241A2D94D6E6005C4682 /* Exceptions for "NumberCube" folder in "NumberCube" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
config/Info.plist,
);
target = 5E2024072D94D6E4005C4682 /* NumberCube */;
};
......@@ -36,17 +43,28 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8CE25481ABBABE93555912FC /* Pods_NumberCube.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
503599C565E53882511146A3 /* Frameworks */ = {
isa = PBXGroup;
children = (
34EB55E037AD4972285400AD /* Pods_NumberCube.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
5E2023FF2D94D6E4005C4682 = {
isa = PBXGroup;
children = (
5E20240A2D94D6E4005C4682 /* NumberCube */,
5E2024092D94D6E4005C4682 /* Products */,
F26524FDC8FEF19EB25285C8 /* Pods */,
503599C565E53882511146A3 /* Frameworks */,
);
sourceTree = "<group>";
};
......@@ -58,6 +76,15 @@
name = Products;
sourceTree = "<group>";
};
F26524FDC8FEF19EB25285C8 /* Pods */ = {
isa = PBXGroup;
children = (
0BF0289D9C625E25AC92A4B5 /* Pods-NumberCube.debug.xcconfig */,
72041B39D629EC7D4060B7DE /* Pods-NumberCube.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
......@@ -65,9 +92,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 5E20241B2D94D6E6005C4682 /* Build configuration list for PBXNativeTarget "NumberCube" */;
buildPhases = (
9AC3247AF950727C2B5A98C4 /* [CP] Check Pods Manifest.lock */,
5E2024AB2D94E9A4005C4682 /* ShellScript */,
5E2024042D94D6E4005C4682 /* Sources */,
5E2024052D94D6E4005C4682 /* Frameworks */,
5E2024062D94D6E4005C4682 /* Resources */,
F176C46099FA319FF443F650 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
......@@ -77,8 +107,6 @@
5E20240A2D94D6E4005C4682 /* NumberCube */,
);
name = NumberCube;
packageProductDependencies = (
);
productName = NumberCube;
productReference = 5E2024082D94D6E4005C4682 /* NumberCube.app */;
productType = "com.apple.product-type.application";
......@@ -127,6 +155,67 @@
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
5E2024AB2D94E9A4005C4682 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
$SRCROOT/NumberCube/config/R.generated.swift,
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$PODS_ROOT/R.swift/rswift\" generate \"$SRCROOT/NumberCube/config/R.generated.swift\"\n";
};
9AC3247AF950727C2B5A98C4 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-NumberCube-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
F176C46099FA319FF443F650 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-NumberCube/Pods-NumberCube-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-NumberCube/Pods-NumberCube-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NumberCube/Pods-NumberCube-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
5E2024042D94D6E4005C4682 /* Sources */ = {
isa = PBXSourcesBuildPhase;
......@@ -140,25 +229,31 @@
/* Begin XCBuildConfiguration section */
5E20241C2D94D6E6005C4682 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0BF0289D9C625E25AC92A4B5 /* Pods-NumberCube.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = L275Z886SW;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = NumberCube/Info.plist;
INFOPLIST_FILE = NumberCube/config/Info.plist;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UIMainStoryboardFile = Main;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = yxf.number.cube.NumberCube;
PRODUCT_BUNDLE_IDENTIFIER = yxf.number.cube;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = debug;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
......@@ -167,25 +262,31 @@
};
5E20241D2D94D6E6005C4682 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 72041B39D629EC7D4060B7DE /* Pods-NumberCube.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = L275Z886SW;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = NumberCube/Info.plist;
INFOPLIST_FILE = NumberCube/config/Info.plist;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UIMainStoryboardFile = Main;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = yxf.number.cube.NumberCube;
PRODUCT_BUNDLE_IDENTIFIER = yxf.number.cube;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = debug;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
......@@ -229,7 +330,7 @@
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
......@@ -244,7 +345,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.2;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
......@@ -292,7 +393,7 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
......@@ -301,7 +402,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.2;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
......
......@@ -7,7 +7,7 @@
<key>NumberCube.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
<integer>11</integer>
</dict>
</dict>
</dict>
......
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:NumberCube.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
//
// AppDelegate.swift
// NumberCube
//
// Created by ilCode on 2025/3/27.
//
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
</dict>
</plist>
//
// SceneDelegate.swift
// NumberCube
//
// Created by ilCode on 2025/3/27.
//
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_cube_normal.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_cube_normal@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_cube_normal@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_cube_selected.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_cube_selected@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_cube_selected@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_para_normal.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_para_normal@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_para_normal@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_para_selected.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_para_selected@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_para_selected@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_set_normal.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_set_normal@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_set_normal@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_set_selected.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_set_selected@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_set_selected@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSMinimumSystemVersion</key>
<string>12.0</string>
</dict>
</plist>
//
// This is a generated file, do not edit!
// Generated by R.swift, see https://github.com/mac-cain13/R.swift
//
import Foundation
import RswiftResources
import UIKit
private class BundleFinder {}
let R = _R(bundle: Bundle(for: BundleFinder.self))
struct _R {
let bundle: Foundation.Bundle
var color: color { .init(bundle: bundle) }
var image: image { .init(bundle: bundle) }
var file: file { .init(bundle: bundle) }
var storyboard: storyboard { .init(bundle: bundle) }
func color(bundle: Foundation.Bundle) -> color {
.init(bundle: bundle)
}
func image(bundle: Foundation.Bundle) -> image {
.init(bundle: bundle)
}
func file(bundle: Foundation.Bundle) -> file {
.init(bundle: bundle)
}
func storyboard(bundle: Foundation.Bundle) -> storyboard {
.init(bundle: bundle)
}
func validate() throws {
try self.storyboard.validate()
}
struct project {
let developmentRegion = "en"
}
/// This `_R.color` struct is generated, and contains static references to 1 colors.
struct color {
let bundle: Foundation.Bundle
/// Color `AccentColor`.
var accentColor: RswiftResources.ColorResource { .init(name: "AccentColor", path: [], bundle: bundle) }
}
/// This `_R.image` struct is generated, and contains static references to 6 images.
struct image {
let bundle: Foundation.Bundle
/// Image `ic_cube_normal`.
var ic_cube_normal: RswiftResources.ImageResource { .init(name: "ic_cube_normal", path: [], bundle: bundle, locale: nil, onDemandResourceTags: nil) }
/// Image `ic_cube_selected`.
var ic_cube_selected: RswiftResources.ImageResource { .init(name: "ic_cube_selected", path: [], bundle: bundle, locale: nil, onDemandResourceTags: nil) }
/// Image `ic_para_normal`.
var ic_para_normal: RswiftResources.ImageResource { .init(name: "ic_para_normal", path: [], bundle: bundle, locale: nil, onDemandResourceTags: nil) }
/// Image `ic_para_selected`.
var ic_para_selected: RswiftResources.ImageResource { .init(name: "ic_para_selected", path: [], bundle: bundle, locale: nil, onDemandResourceTags: nil) }
/// Image `ic_set_normal`.
var ic_set_normal: RswiftResources.ImageResource { .init(name: "ic_set_normal", path: [], bundle: bundle, locale: nil, onDemandResourceTags: nil) }
/// Image `ic_set_selected`.
var ic_set_selected: RswiftResources.ImageResource { .init(name: "ic_set_selected", path: [], bundle: bundle, locale: nil, onDemandResourceTags: nil) }
}
/// This `_R.file` struct is generated, and contains static references to 1 resource files.
struct file {
let bundle: Foundation.Bundle
/// Resource file `GKNavigationBarSwift.bundle`.
var gkNavigationBarSwiftBundle: RswiftResources.FileResource { .init(name: "GKNavigationBarSwift", pathExtension: "bundle", bundle: bundle, locale: LocaleReference.none) }
}
/// This `_R.storyboard` struct is generated, and contains static references to 1 storyboards.
struct storyboard {
let bundle: Foundation.Bundle
var launchScreen: launchScreen { .init(bundle: bundle) }
func launchScreen(bundle: Foundation.Bundle) -> launchScreen {
.init(bundle: bundle)
}
func validate() throws {
try self.launchScreen.validate()
}
/// Storyboard `LaunchScreen`.
struct launchScreen: RswiftResources.StoryboardReference, RswiftResources.InitialControllerContainer {
typealias InitialController = UIKit.UIViewController
let bundle: Foundation.Bundle
let name = "LaunchScreen"
func validate() throws {
}
}
}
}
\ No newline at end of file
//
// UIWindow+Ext.swift
// NumberCube
//
// Created by ilCode on 2025/3/27.
//
import Foundation
extension UIWindow {
static var isLandscape: Bool {
if #available(iOS 13.0, *) {
return UIApplication.shared.windows
.first?
.windowScene?
.interfaceOrientation
.isLandscape ?? false
} else {
return UIApplication.shared.statusBarOrientation.isLandscape
}
}
}
//
// EntryController.swift
// NumberCube
//
// Created by ilCode on 2025/3/27.
//
import UIKit
//MARK: - life
class EntryController: UITabBarController {
private var curIndex: Int = 0
private lazy var tabBarItemViews = [UIView]()
override func viewDidLoad() {
super.viewDidLoad()
// 设置tabbar背景色 && 隐藏tabbar分割线
tabBar.backgroundImage = UIImage()
tabBar.shadowImage = UIImage()
tabBar.backgroundColor = .white
// 设置tabbar选中及未选中的文字颜色
tabBar.tintColor = kMasterColor
tabBar.unselectedItemTintColor = hexColor("AAAAAA")
addController(rootVC: HomeController(), title: "魔方", image: R.image.ic_cube_normal(), selectedImage: R.image.ic_cube_selected())
addController(rootVC: ParaController(), title: "参数", image: R.image.ic_para_normal(), selectedImage: R.image.ic_para_selected())
addController(rootVC: SettingController(), title: "设置", image: R.image.ic_set_normal(), selectedImage: R.image.ic_set_selected())
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// 保存tabBarItemView
for tabBarItemView in tabBar.subviews {
if tabBarItemView.isKind(of: NSClassFromString("UITabBarButton")!) {
tabBarItemViews.append(tabBarItemView)
}
}
}
}
//MARK: - UITabBarDelegate
extension EntryController {
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
guard let itemIndex = tabBar.items?.firstIndex(of: item),
itemIndex != curIndex else { return }
zoomAnimate(itemViews: tabBarItemViews, index: itemIndex)
curIndex = itemIndex
}
}
//MARK: - Private
extension EntryController {
/// 添加缩放动画
/// - Parameters:
/// - itemViews: itemViews
/// - index: index
private func zoomAnimate(itemViews: [UIView], index: Int) {
guard itemViews.count > 0 else { return }
let zoomAni = CABasicAnimation(keyPath: "transform.scale")
zoomAni.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
zoomAni.duration = 0.2;
zoomAni.repeatCount = 1;
zoomAni.autoreverses = true;
zoomAni.fromValue = 0.9
zoomAni.toValue = 1.1
itemViews[index].layer.add(zoomAni, forKey: nil)
}
/// 添加子控制器
/// - Parameters:
/// - rootVC: rootVC
/// - title: title
/// - image: image
/// - selectedImage: selectedImage
private func addController(rootVC: UIViewController, title: String, image: UIImage?, selectedImage: UIImage?) {
let navi = UINavigationController(rootVC: rootVC)
navi.tabBarItem = UITabBarItem(title: title, image: image, selectedImage: selectedImage)
navi.tabBarItem.image = navi.tabBarItem.image?.withRenderingMode(.alwaysOriginal)
navi.tabBarItem.selectedImage = navi.tabBarItem.selectedImage?.withRenderingMode(.alwaysOriginal)
addChild(navi)
}
}
//
// ViewController.swift
// NumCubeController.swift
// NumberCube
//
// Created by ilCode on 2025/3/27.
......@@ -7,13 +7,10 @@
import UIKit
class ViewController: UIViewController {
class HomeController: NcBaseController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
}
//
// NcAppDelegate.swift
// NumberCube
//
// Created by ilCode on 2025/3/27.
//
import UIKit
@main
class NcAppDelegate: UIResponder, UIApplicationDelegate {
var kWindow: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Thread.sleep(forTimeInterval: 2)
// initLogger()
initNaviBar()
initWindow()
return true
}
}
extension NcAppDelegate {
// private func initLogger() {
// _ = HiLoggerTools()
// }
private func initNaviBar() {
GKConfigure.setupCustom {
// 导航栏标题颜色
$0.titleColor = hexColor("#0A120A")
// 导航栏标题字体
$0.titleFont = ncFont(18, isBold: true)
// 导航栏返回按钮样式
$0.backStyle = .black
// 状态栏样式
$0.statusBarStyle = .lightContent
// 导航栏左右item间距
$0.gk_navItemLeftSpace = 15
$0.gk_navItemRightSpace = 15
// 是否恢复系统导航
$0.gk_restoreSystemNavBar = true
// 设置导航栏背景色
// $0.backgroundImage = R.image.navibar_bg()
// 缩放配置
$0.gk_scaleX = 0.90
$0.gk_scaleY = 0.92
// 开启全局UIScrollView处理
$0.gk_openScrollViewGestureHandle = true
// 跳转的时候隐藏标签栏
$0.gk_hidesBottomBarWhenPushed = true
}
}
private func initWindow() {
kWindow = UIWindow.init(frame: UIScreen.main.bounds)
kWindow?.backgroundColor = .white
kWindow?.rootViewController = EntryController()
kWindow?.makeKeyAndVisible()
}
}
//
// NcBaseController.swift
// NumberCube
//
// Created by ilCode on 2025/3/27.
//
import UIKit
class NcBaseController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
gk_maxPopDistance = 100
view.backgroundColor = mainBgColor
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .darkContent
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}
}
//
// ParaController.swift
// NumberCube
//
// Created by ilCode on 2025/3/27.
//
import UIKit
class ParaController: NcBaseController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
//
// SettingController.swift
// NumberCube
//
// Created by ilCode on 2025/3/27.
//
import UIKit
class SettingController: NcBaseController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
//
// NcColor.swift
// NumberCube
//
// Created by ilCode on 2025/3/27.
//
func hexColor(_ hexStr: String) -> UIColor? {
return UIColor(hexString: hexStr)
}
func hexColorA(_ hexStr: String, _ alpha: Float) -> UIColor? {
return UIColor(hexString: hexStr, alpha: alpha)
}
let kMasterColor = hexColor("1296db")
let mainBgColor = hexColor("F5F5F5")
//
// NcFont.swift
// NumberCube
//
// Created by ilCode on 2025/3/27.
//
import Foundation
func ncFont(_ ofSize: CGFloat, isBold: Bool = false) -> UIFont {
return isBold ? UIFont.boldSystemFont(ofSize: ofSize) : UIFont.systemFont(ofSize: ofSize)
}
//
// NcImport.swift
// NumberCube
//
// Created by ilCode on 2025/3/27.
//
@_exported import SnapKit
@_exported import PinLayout
@_exported import Then
@_exported import CocoaLumberjack
@_exported import Toast_Swift
@_exported import SwiftHEXColors
//
// Bundle+GKExtension.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2023/7/21.
//
import Foundation
extension Bundle {
static var gk_bundle: Bundle? {
normalModule ?? spmModule
}
private static var normalModule: Bundle? = {
let bundleName = "GKNavigationBarSwift"
var candidates = [
// Bundle should be present here when the package is linked into an App.
Bundle.main.resourceURL,
// Bundle should be present here when the package is linked into a framework.
Bundle(for: GKNavigationBarConfigure.self).resourceURL,
// For command-line tools.
Bundle.main.bundleURL,
]
#if SWIFT_PACKAGE
// For SWIFT_PACKAGE.
candidates.append(Bundle.module.bundleURL)
#endif
for candidate in candidates {
let bundlePath = candidate?.appendingPathComponent(bundleName + ".bundle")
if let bundle = bundlePath.flatMap(Bundle.init(url:)) {
return bundle
}
}
return nil
}()
private static var spmModule: Bundle? = {
let bundleName = "GKNavigationBarSwift_GKNavigationBarSwift"
let candidates = [
// Bundle should be present here when the package is linked into an App.
Bundle.main.resourceURL,
// Bundle should be present here when the package is linked into a framework.
Bundle(for: GKNavigationBarConfigure.self).resourceURL,
// For command-line tools.
Bundle.main.bundleURL,
]
for candidate in candidates {
let bundlePath = candidate?.appendingPathComponent(bundleName + ".bundle")
if let bundle = bundlePath.flatMap(Bundle.init(url:)) {
return bundle
}
}
return nil
}()
}
//
// GKBaseAnimatedTransition.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/3/24.
// Copyright © 2020 QuintGao. All rights reserved.
//
import UIKit
open class GKBaseAnimatedTransition: NSObject {
open var isScale = false
open var shadowView: UIView!
open var transitionContext: UIViewControllerContextTransitioning!
open var containerView: UIView!
open var fromViewController: UIViewController!
open var toViewController: UIViewController!
open var isHideTabBar = false
open class func transition(with scale: Bool) -> GKBaseAnimatedTransition {
return self.init(scale: scale)
}
required public init(scale: Bool) {
self.isScale = scale
}
}
extension GKBaseAnimatedTransition: UIViewControllerAnimatedTransitioning {
// MARK - UIViewControllerAnimatedTransitioning
open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return TimeInterval(UINavigationController.hideShowBarDuration)
}
open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
let fromVC = transitionContext.viewController(forKey: .from)
let toVC = transitionContext.viewController(forKey: .to)
self.containerView = containerView
self.fromViewController = fromVC
self.toViewController = toVC
self.transitionContext = transitionContext
animateTransition()
}
public func animationDuration() -> TimeInterval {
return self.transitionDuration(using: self.transitionContext)
}
@objc open func animateTransition() {
// SubClass Implementation
}
public func completeTransition() {
guard let transitionContext = self.transitionContext else { return }
transitionContext .completeTransition(!transitionContext.transitionWasCancelled)
}
}
extension UIViewController {
fileprivate struct AssociatedKeys {
static var defCaptureImage: Void?
}
public var gk_captureImage: UIImage? {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.defCaptureImage) else { return nil }
return obj as? UIImage
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.defCaptureImage, newValue)
}
}
}
//
// GKNavigationBarConfigure.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/3/24.
// Copyright © 2020 QuintGao. All rights reserved.
//
import UIKit
public let GKConfigure = GKNavigationBarConfigure.shared
// 配置类宏定义
open class GKNavigationBarConfigure : NSObject {
/// 导航栏背景色
open var backgroundColor: UIColor?
/// 导航栏背景图片,默认nil,优先级高于backgroundColor
open var backgroundImage: UIImage?
/// 暗黑模式下的背景图片,默认nil,优先级高于backgroundColor
open var darkBackgroundImage: UIImage?
/// 导航栏分割线颜色,默认nil,使用系统颜色
open var lineColor: UIColor?
/// 导航栏分割线图片,默认nil,优先级高于lineColor
open var lineImage: UIImage?
/// 暗黑模式下的分割线图片,默认nil,优先级高于lineColor
open var darkLineImage: UIImage?
/// 导航栏分割线是否隐藏,默认NO
open var lineHidden: Bool = false
/// 导航栏标题颜色,默认黑色
open var titleColor: UIColor?
/// 导航栏标题字体,默认系统字体17
open var titleFont: UIFont?
/// 返回按钮图片,默认nil,优先级高于backStyle
open var backImage: UIImage?
/// 暗黑模式下的返回图片,mornil,优先级高于backStyle
open var darkBackImage: UIImage?
/// backStyle为GKNavigationBarBackStyle.black时对应的图片,默认btn_back_black
open var blackBackImage: UIImage?
/// backStyle为GKNavigationBarBackStyle.white时对应的图片,默认btn_black_white
open var whiteBackImage: UIImage?
/// 返回按钮样式
open var backStyle: GKNavigationBarBackStyle = .none
/// 是否禁止导航栏左右item间距调整,默认是NO
/// 1.4.0版本之后,只对带有GKNavigationBar的控制器有效
open var gk_disableFixSpace: Bool = false
/// 是否开启普通控制器的导航栏item间距调整,只能在对应的控制器中开启
open var gk_openSystemFixSpace: Bool = false
/// 导航栏左侧按钮距屏幕左边间距,默认是0,可自行调整
open var gk_navItemLeftSpace: CGFloat = 0.0
/// 导航栏右侧按钮距屏幕右边间距,默认是0,可自行调整
open var gk_navItemRightSpace: CGFloat = 0.0
/// 是否隐藏状态栏,默认NO
open var statusBarHidden: Bool = false
/// 状态栏类型,默认UIStatusBarStyleDefault
open var statusBarStyle: UIStatusBarStyle = .default
/// 用于恢复系统导航栏的显示,默认NO
open var gk_restoreSystemNavBar: Bool = false
/// 快速滑动时的灵敏度,默认0.7
open var gk_snapMovementSensitivity: CGFloat = 0.7
/// 左滑push过渡临界值,默认0.3,大于此值完成push操作
open var gk_pushTransitionCriticalValue: CGFloat = 0.3
/// 右滑pop过渡临界值,默认0.5,大于此值完成pop操作
open var gk_popTransitionCriticalValue: CGFloat = 0.5
/// 控制x、y轴的缩放程度,默认(0.95,0.97)
open var gk_scaleX: CGFloat = 0.95
open var gk_scaleY: CGFloat = 0.97
/// 需要屏蔽手势处理的VC,默认nil,支持UIViewController和String
open var shiledGuestureVCs: [Any]?
/// 全局开启UIScrollView手势处理,默认false
/// 如果设置为YES,可在单个UIScrollView中通过gk_openGestureHandle关闭
open var gk_openScrollViewGestureHandle: Bool = false
/// 设置push时是否隐藏tabbar,默认NO
open var gk_hidesBottomBarWhenPushed: Bool = false
/// 导航栏左右间距,内部使用
open var disableFixSpace: Bool = false
open var navItemLeftSpace: CGFloat = 0
open var navItemRightSpace: CGFloat = 0
/// 单例,设置一次全局使用
public static let shared: GKNavigationBarConfigure = {
let instance = GKNavigationBarConfigure()
// setup code
return instance
}()
private static let awake: Void = {
UIViewController.gkAwake()
UINavigationController.gkChildAwake()
UINavigationItem.gkAwake()
NSObject.gkObjectAwake()
UIScrollView.gkAwake()
UIViewController.gkGestureAwake()
UINavigationController.gkGestureChildAwake()
}()
/// 设置默认配置
open func setupDefault() {
GKNavigationBarConfigure.awake
backgroundColor = .white
titleColor = .black
titleFont = UIFont.boldSystemFont(ofSize: 17.0)
blackBackImage = UIImage.gk_image(with: "btn_back_black")
whiteBackImage = UIImage.gk_image(with: "btn_back_white")
backStyle = .black
gk_disableFixSpace = false
gk_navItemLeftSpace = 0
gk_navItemRightSpace = 0
navItemLeftSpace = 0
navItemRightSpace = 0
statusBarHidden = false
statusBarStyle = .default
gk_snapMovementSensitivity = 0.7
gk_pushTransitionCriticalValue = 0.3
gk_popTransitionCriticalValue = 0.5
gk_scaleX = 0.95
gk_scaleY = 0.97
}
open func awake() {
GKNavigationBarConfigure.awake
}
/// 设置自定义配置,此方法只需调用一次
/// @param block 配置回调
open func setupCustom(_ block: @escaping (GKNavigationBarConfigure) -> Void) {
setupDefault()
block(self)
disableFixSpace = gk_disableFixSpace
navItemLeftSpace = gk_navItemLeftSpace
navItemRightSpace = gk_navItemRightSpace
}
/// 更新配置
/// @param block 配置回调
open func update(_ block: @escaping (GKNavigationBarConfigure) -> Void) {
block(self)
}
open func visibleViewController() -> UIViewController? {
return GKDevice.keyWindow()?.rootViewController?.gk_findCurrentViewController(true)
}
/// 获取当前item修复间距
open func gk_fixedSpace() -> CGFloat {
// 经测试发现iPhone 12,iPhone 12 Pro,iPhone 14 Pro默认导航栏间距是16,需要单独处理
if GKDevice.is61InchScreenAndiPhone12Later || GKDevice.is61InchScreenAndiPhone14Pro { return 16 }
return GKDevice.width > 375.0 ? 20 : 16
}
open func fixNavItemSpaceDisabled() -> Bool {
return self.gk_disableFixSpace && !self.gk_openSystemFixSpace
}
// 内部方法
open func isVelocityInsensitivity(_ velocity: CGFloat) -> Bool {
return (abs(velocity) - (1000.0 * (1 - self.gk_snapMovementSensitivity))) > 0;
}
/// 获取某个view的截图
open func getCapture(with view: UIView) -> UIImage? {
if view.bounds.size.width <= 0 || view.bounds.size.height <= 0 { return nil }
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale)
view.drawHierarchy(in: view.bounds, afterScreenUpdates: false)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
open class GKDevice {
public static let deviceModel: String = {
if isSimulator, let identifier = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
return identifier
}
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)))
}
return identifier
}()
public static func isZoomedMode() -> Bool {
if !isIPhone { return false }
let nativeScale = UIScreen.main.nativeScale
var scale = UIScreen.main.scale
// 对于所有的Plus系列iPhone,屏幕物理像素低于软件层面的渲染像素,不管标准模式还是放大模式,nativeScale均小于scale,所以需要特殊处理才能准确区分放大模式
let shouldBeDownsampledDevice = __CGSizeEqualToSize(UIScreen.main.nativeBounds.size, CGSize(width: 1080, height: 1920))
if shouldBeDownsampledDevice {
scale /= 1.15
}
return nativeScale > scale
}
public static let isIPad: Bool = {
return UIDevice.current.userInterfaceIdiom == .pad
}()
public static let isIPod: Bool = {
let model = UIDevice.current.model as NSString
return model.range(of: "iPod touch").location != NSNotFound
}()
public static let isIPhone: Bool = {
let model = UIDevice.current.model as NSString
return model.range(of: "iPhone").location != NSNotFound
}()
public static let isSimulator: Bool = {
#if targetEnvironment(simulator)
return true
#else
return false
#endif
}()
public static let isMac: Bool = {
#if IOS14_SDK_ALLOWED
if #available(iOS 14.0, *) {
return ProcessInfo.processInfo.isiOSAppOnMac || ProcessInfo.processInfo.isMacCatalystApp
}
#endif
if #available(iOS 13.0, *) {
return ProcessInfo.processInfo.isMacCatalystApp
}
return false
}()
/// 带物理凹槽的刘海屏或使用 Home Indicator 类型的设备
public static let isNotchedScreen: Bool = {
if #available(iOS 11.0, *) {
var window = keyWindow()
if window == nil {
// keyWindow还没有创建时,通过创建临时window获取安全区域
window = UIWindow(frame: UIScreen.main.bounds)
if window!.safeAreaInsets.bottom <= 0 {
let viewController = UIViewController()
window?.rootViewController = viewController
}
}
if window!.safeAreaInsets.bottom > 0 {
return true
}
} else {
return false
}
return false
}()
/// 将屏幕分为普通和紧凑两种,这个方法用于判断普通屏幕(也即大屏幕)
public static func isRegularScreen() -> Bool {
return isIPad || (!isZoomedMode() && (is67InchScreenAndiPhone14ProMax || is67InchScreen || is65InchScreen || is61InchScreen || is55InchScreen))
}
/// 是否是横屏
public static func isLandScape() -> Bool {
if #available(iOS 13.0, *) {
// 在 iOS 13 及更高版本中,使用 traitCollection
guard let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else {
// 如果没有找到 key window,则返回 false
return false
}
let horizontalSizeClass = window.traitCollection.horizontalSizeClass
// 横屏时,horizontalSizeClass 通常是 .regular
return horizontalSizeClass == .regular
} else {
// 在 iOS 12 及更早版本中,使用已弃用的 statusBarOrientation
return UIApplication.shared.statusBarOrientation.isLandscape
}
}
public static func statusBarNavBarHeight() -> CGFloat {
// 适配灵动岛状态栏高度
var statusBarHeight: CGFloat = 0
if #available(iOS 13.0, *) {
let window = UIApplication.shared.windows.first
let topPadding = window?.safeAreaInsets.top
statusBarHeight = topPadding ?? 20.0
} else {
statusBarHeight = UIApplication.shared.statusBarFrame.height
}
return statusBarHeight + navBarHeight()
}
public static func navBarHeight() -> CGFloat {
if isIPad {
if let version = version, version >= 12.0 {
return 50
}else {
return 44
}
}else {
if isLandScape() {
return isRegularScreen() ? 44 : 32
}else {
return 44
}
}
}
public static func navBarHeightNonFullScreen() -> CGFloat {
return 56
}
public static func tabBarHeight() -> CGFloat {
var tabBarHeight: CGFloat = 0
if isIPad {
if isNotchedScreen {
tabBarHeight = 65
}else {
if let version = version, version >= 12.0 {
tabBarHeight = 50
}else {
tabBarHeight = 49
}
}
}else {
if isLandScape() {
if isRegularScreen() {
tabBarHeight = 49
}else {
tabBarHeight = 32
}
}else {
tabBarHeight = 49
}
tabBarHeight += safeAreaInsertsForDeviceWithNotch().bottom
}
return tabBarHeight
}
public static func safeAreaInsets() -> UIEdgeInsets {
var safeAreaInsets = UIEdgeInsets.zero
if #available(iOS 11.0, *) {
var window = keyWindow()
if window == nil {
// keyWindow还没有创建时,通过创建临时window获取安全区域
window = UIWindow(frame: UIScreen.main.bounds)
if window!.safeAreaInsets.bottom <= 0 {
let viewController = UIViewController()
window?.rootViewController = viewController
}
}
safeAreaInsets = window!.safeAreaInsets
}
return safeAreaInsets
}
static func STATUSBAR_HEIGHT() -> CGFloat {
// 适配灵动岛状态栏高度
var statusBarHeight: CGFloat = 0
if #available(iOS 13.0, *) {
let window = UIApplication.shared.windows.first
let topPadding = window?.safeAreaInsets.top
statusBarHeight = topPadding ?? 20.0
} else {
statusBarHeight = UIApplication.shared.statusBarFrame.height
}
return statusBarHeight
}
public static func statusBarFrame() -> CGRect {
var statusBarFrame = CGRect.zero
if #available(iOS 13.0, *) {
statusBarFrame = keyWindow()?.windowScene?.statusBarManager?.statusBarFrame ?? .zero
}
if statusBarFrame == .zero {
let statusBarH = isNotchedScreen ? 44 : 20
statusBarFrame = CGRect(x: 0, y: 0, width: Int(UIScreen.main.bounds.size.width), height: statusBarH)
}
return statusBarFrame
}
public static func keyWindow() -> UIWindow? {
var window: UIWindow?
if #available(iOS 13.0, *) {
window = UIApplication.shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?.windows
.filter({$0.isKeyWindow}).first
}
if window == nil {
window = UIApplication.shared.delegate?.window ?? nil
}
return window
}
public static func safeAreaInsertsForDeviceWithNotch() -> UIEdgeInsets {
if !isNotchedScreen {
return .zero
}
if isIPad {
return UIEdgeInsets(top: 24, left: 0, bottom: 20, right: 0)
}
let dict = [
// iPhone 14
"iPhone14,7": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 47, left: 0, bottom: 34, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 47, bottom: 21, right: 47)],
"iPhone14,7-Zoom": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 48, left: 0, bottom: 28, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 48, bottom: 21, right: 48)],
// iPhone 14 Plus
"iPhone14,8": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 47, left: 0, bottom: 34, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 47, bottom: 21, right: 47)],
"iPhone14,8-Zoom": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 41, left: 0, bottom: 30, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 41, bottom: 21, right: 41)],
// iPhone 14 Pro
"iPhone15,2": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 59, left: 0, bottom: 34, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 59, bottom: 21, right: 59)],
"iPhone15,2-Zoom": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 48, left: 0, bottom: 28, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 48, bottom: 21, right: 48)],
// iPhone 14 Pro Max
"iPhone15,3": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 59, left: 0, bottom: 34, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 59, bottom: 21, right: 59)],
"iPhone15,3-Zoom": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 51, left: 0, bottom: 31, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 51, bottom: 21, right: 51)],
// iPhone 13 mini
"iPhone14,4": [UIInterfaceOrientation.portrait : UIEdgeInsets(top: 50, left: 0, bottom: 34, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 50, bottom: 21, right: 50)],
"iPhone14,4-Zoom": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 43, left: 0, bottom: 29, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 43, bottom: 21, right: 43)],
// iPhone 13
"iPhone14,5": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 47, left: 0, bottom: 34, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 47, bottom: 21, right: 47)],
"iPhone14,5-Zoom": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 39, left: 0, bottom: 28, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 39, bottom: 2, right: 39)],
// iPhone 13 Pro
"iPhone14,2": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 47, left: 0, bottom: 34, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 47, bottom: 21, right: 47)],
"iPhone14,2-Zoom": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 39, left: 0, bottom: 28, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 39, bottom: 21, right: 39)],
// iPhone 13 Pro Max
"iPhone14,3": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 47, left: 0, bottom: 34, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 47, bottom: 21, right: 47)],
"iPhone14,3-Zoom": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 41, left: 0, bottom: 29 + 2.0 / 3.0, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 41, bottom: 21, right: 41)],
// iPhone 12 mini
"iPhone13,1": [UIInterfaceOrientation.portrait: UIEdgeInsets(top: 50, left: 0, bottom: 34, right: 0),
UIInterfaceOrientation.landscapeLeft: UIEdgeInsets(top: 0, left: 50, bottom: 21, right: 50)],
"iPhone13,1-Zoom": [.portrait: UIEdgeInsets(top: 43, left: 0, bottom: 29, right: 0),
.landscapeLeft: UIEdgeInsets(top: 0, left: 43, bottom: 21, right: 43)],
// iPhone 12
"iPhone13,2": [.portrait: UIEdgeInsets(top: 47, left: 0, bottom: 34, right: 0),
.landscapeLeft: UIEdgeInsets(top: 0, left: 47, bottom: 21, right: 47)],
"iPhone13,2-Zoom": [.portrait: UIEdgeInsets(top: 39, left: 0, bottom: 28, right: 0),
.landscapeLeft: UIEdgeInsets(top: 0, left: 39, bottom: 21, right: 39)],
// iPhone 12 Pro
"iPhone13,3": [.portrait: UIEdgeInsets(top: 47, left: 0, bottom: 34, right: 0),
.landscapeLeft: UIEdgeInsets(top: 0, left: 47, bottom: 21, right: 47)],
"iPhone13,3-Zoom": [.portrait: UIEdgeInsets(top: 39, left: 0, bottom: 28, right: 0),
.landscapeLeft: UIEdgeInsets(top: 0, left: 39, bottom: 21, right: 39)],
// iPhone 12 Pro Max
"iPhone13,4": [.portrait: UIEdgeInsets(top: 47, left: 0, bottom: 34, right: 0),
.landscapeLeft: UIEdgeInsets(top: 0, left: 47, bottom: 21, right: 47)],
"iPhone13,4-Zoom": [.portrait: UIEdgeInsets(top: 41, left: 0, bottom: 29 + 2.0 / 3.0, right: 0),
.landscapeLeft: UIEdgeInsets(top: 0, left: 41, bottom: 21, right: 41)],
// iPhone 11
"iPhone12,1": [.portrait: UIEdgeInsets(top: 48, left: 0, bottom: 34, right: 0),
.landscapeLeft: UIEdgeInsets(top: 0, left: 48, bottom: 21, right: 48)],
"iPhone12,1-Zoom": [.portrait: UIEdgeInsets(top: 44, left: 0, bottom: 31, right: 0),
.landscapeLeft: UIEdgeInsets(top: 0, left: 44, bottom: 21, right: 44)],
// iPhone 11 Pro Max
"iPhone12,5": [.portrait: UIEdgeInsets(top: 44, left: 0, bottom: 34, right: 0),
.landscapeLeft: UIEdgeInsets(top: 0, left: 44, bottom: 21, right: 44)],
"iPhone12,5-Zoom": [.portrait: UIEdgeInsets(top: 40, left: 0, bottom: 30 + 2.0 / 3.0, right: 0),
.landscapeLeft: UIEdgeInsets(top: 0, left: 40, bottom: 21, right: 40)]
]
var deviceKey = deviceModel
if dict[deviceKey] == nil {
deviceKey = "iPhone15,2" // 默认按最新的机型处理,因为新出的设备肯定更大概率与上一代设备相似
}
if isZoomedMode() {
deviceKey = deviceKey + "-Zoom"
}
var orientationKey = UIInterfaceOrientation.unknown
let value = dict[deviceKey]
var insets = value![orientationKey]!
if (UIWindow.isLandscape) {
orientationKey = .landscapeLeft
insets = UIEdgeInsets(top: insets.top, left: insets.right, bottom: insets.bottom, right: insets.left)
} else {
orientationKey = .portrait
insets = UIEdgeInsets(top: insets.bottom, left: insets.left, bottom: insets.top, right: insets.right)
}
return insets
}
}
extension GKDevice {
public static let version: Double? = {
return Double(UIDevice.current.systemVersion)
}()
public static let width: CGFloat = {
min(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height)
}()
public static let height: CGFloat = {
max(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height)
}()
// MARK - Screen
/// iPhone 14 Pro Max
public static let is67InchScreenAndiPhone14ProMax: Bool = {
return width == _67InchAndiPhone14ProMax.width && height == _67InchAndiPhone14ProMax.height
}()
/// iPhone 12 Pro Max
public static let is67InchScreen: Bool = {
return width == _67Inch.width && height == _67Inch.height
}()
/// iPhone XS Max / 11 Pro Max
public static let is65InchScreen: Bool = {
// 由于 iPhone XS Max、iPhone 11 Pro Max 这两款机型和 iPhone XR 的屏幕宽高是一致的,我们通过机器的 Identifier 加以区别
return (width == _65Inch.width && height == _65Inch.height && (deviceModel == "iPhone11,4" || deviceModel == "iPhone11,6" || deviceModel == "iPhone12,5"))
}()
/// iPhone 14 Pro
public static let is61InchScreenAndiPhone14Pro: Bool = {
return width == _61InchAndiPhone14Pro.width && height == _61InchAndiPhone14Pro.height
}()
/// iPhone 12 / 12 Pro
public static let is61InchScreenAndiPhone12Later: Bool = {
return width == _61InchAndiPhone12Later.width && height == _61InchAndiPhone12Later.height
}()
/// iPhone XR / 11
public static let is61InchScreen: Bool = {
return (width == _61Inch.width && height == _61Inch.height && (deviceModel == "iPhone11,8" || deviceModel == "iPhone12,1"))
}()
/// iPhone X / XS / 11 Pro
public static let is58InchScreen: Bool = {
// iPhone XS 和 iPhone X 的物理尺寸是一致的,因此无需比较机器 Identifier
return width == _58Inch.width && height == _58Inch.height
}()
/// iPhone 6,6s,7,8 Plus
public static let is55InchScreen: Bool = {
return width == _55Inch.width && height == _55Inch.height
}()
/// iPhone 12 mini
public static let is54InchScreen: Bool = {
return width == _54Inch.width && height == _54Inch.height
}()
/// iPhone 6,6s,7,8,SE2
public static let is47InchScreen: Bool = {
return width == _47Inch.width && height == _47Inch.height
}()
/// iPhone 5,5s,5c,SE
public static let is40InchScreen: Bool = {
return width == _40Inch.width && height == _40Inch.height
}()
/// iPhone 4
public static let is35InchScreen: Bool = {
return width == _35Inch.width && height == _35Inch.height
}()
public static let _67InchAndiPhone14ProMax: CGSize = {
return CGSize(width: 430, height: 932)
}()
public static let _67Inch: CGSize = {
return CGSize(width: 428, height: 926)
}()
public static let _65Inch: CGSize = {
return CGSize(width: 414, height: 896)
}()
public static let _61InchAndiPhone14Pro: CGSize = {
return CGSize(width: 393, height: 852)
}()
public static let _61InchAndiPhone12Later: CGSize = {
return CGSize(width: 390, height: 844)
}()
public static let _61Inch: CGSize = {
return CGSize(width: 414, height: 896)
}()
public static let _58Inch: CGSize = {
return CGSize(width: 375, height: 812)
}()
public static let _55Inch: CGSize = {
return CGSize(width: 414, height: 736)
}()
public static let _54Inch: CGSize = {
return CGSize(width: 375, height: 812)
}()
public static let _47Inch: CGSize = {
return CGSize(width: 375, height: 667)
}()
public static let _40Inch: CGSize = {
return CGSize(width: 320, height: 568)
}()
public static let _35Inch: CGSize = {
return CGSize(width: 320, height: 480)
}()
}
//
// GKNavigationBarDefine.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/3/24.
// Copyright © 2020 QuintGao. All rights reserved.
//
import UIKit
/// 导航栏间距,用于不同控制器之间的间距
public let GKNavigationBarItemSpace: CGFloat = -1.0
public enum GKNavigationBarBackStyle {
case none
case black
case white
}
public func gk_swizzled_instanceMethod(_ prefix: String, oldClass: Swift.AnyClass!, oldSelector: String, newClass: Swift.AnyClass) {
let newSelector = prefix + "_" + oldSelector;
let originalSelector = NSSelectorFromString(oldSelector)
let swizzledSelector = NSSelectorFromString(newSelector)
let originalMethod = class_getInstanceMethod(oldClass, originalSelector)
let swizzledMethod = class_getInstanceMethod(newClass, swizzledSelector)
let isAdd = class_addMethod(oldClass, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))
if isAdd {
class_replaceMethod(newClass, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
}else {
method_exchangeImplementations(originalMethod!, swizzledMethod!)
}
}
public func gk_getAssociatedObject(_ object: Any, _ key: UnsafeRawPointer) -> Any? {
return objc_getAssociatedObject(object, key)
}
public func gk_setAssociatedObject(_ object: Any, _ key: UnsafeRawPointer, _ value: Any?) {
objc_setAssociatedObject(object, key, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
// 定义Awake协议,让需要重新系统方法的类实现该协议
public protocol GKObjectAwakeProtocol: AnyObject {
static func gkObjectAwake()
}
public protocol GKAwakeProtocol: AnyObject {
static func gkAwake()
}
public protocol GKChildAwakeProtocol: AnyObject {
static func gkChildAwake()
}
public protocol GKGestureAwakeProtocol: AnyObject {
static func gkGestureAwake()
}
public protocol GKGestureChildAwakeProtocol: AnyObject {
static func gkGestureChildAwake()
}
// MARK: - Swizzling会改变全局状态,所以用DispatchQueue.once来确保无论多少线程都只会被执行一次
extension DispatchQueue {
private static var onceTracker = [String]()
// Executes a block of code, associated with a unique token, only once. The code is thread safe and will only execute the code once even in the presence of multithreaded calls.
public class func once(token: String, block: () -> Void) {
// 保证被 objc_sync_enter 和 objc_sync_exit 包裹的代码可以有序同步地执行
objc_sync_enter(self)
defer { // 作用域结束后执行defer中的代码
objc_sync_exit(self)
}
if onceTracker.contains(token) {
return
}
onceTracker.append(token)
block()
}
}
//
// GKNavigationBarSwift.h
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/4/11.
// Copyright © 2020 QuintGao. All rights reserved.
//
#import <Foundation/Foundation.h>
//! Project version number for GKNavigationBarSwift.
FOUNDATION_EXPORT double GKNavigationBarSwiftVersionNumber;
//! Project version string for GKNavigationBarSwift.
FOUNDATION_EXPORT const unsigned char GKNavigationBarSwiftVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <GKNavigationBarSwift/PublicHeader.h>
//
// GKNavigationBarSwift.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/3/25.
// Copyright © 2020 QuintGao. All rights reserved.
// Custom navigation bar
import UIKit
open class GKNavigationBar: UINavigationBar {
/// 当前所在的控制器是否隐藏状态栏
public var gk_statusBarHidden: Bool = false
/// 导航栏透明度
public var gk_navBarBackgroundAlpha: CGFloat = 1 {
willSet {
for obj in self.subviews {
if let cls = NSClassFromString("_UIBarBackground") {
if #available(iOS 10.0, *), obj.isKind(of: cls) {
DispatchQueue.main.async {
if obj.alpha != newValue {
obj.alpha = newValue
}
}
}else {
if let navBarBackgroundCls = NSClassFromString("_UINavigationBarBackground") {
if obj.isKind(of: navBarBackgroundCls) {
DispatchQueue.main.async {
if obj.alpha != newValue {
obj.alpha = newValue
}
}
}
}
}
}
}
let isClipsToBounds = (newValue == 0.0)
if self.clipsToBounds != isClipsToBounds {
self.clipsToBounds = isClipsToBounds
}
}
}
/// 导航栏分割线是否隐藏
public var gk_navLineHidden: Bool = false
/// 是否是非全屏控制器
public var gk_nonFullScreen: Bool = false
public override init(frame: CGRect) {
super.init(frame:frame)
self.gk_navBarBackgroundAlpha = 1.0
}
required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
open override func layoutSubviews() {
super.layoutSubviews()
/// 适配iOS11及以上,遍历所有子控件,向下移动状态栏高度
if #available(iOS 11.0, *) {
for obj in self.subviews {
if let cls = NSClassFromString("_UIBarBackground") {
if obj.isKind(of: cls) {
var frame = obj.frame
frame.size.height = self.frame.size.height
obj.frame = frame
}else {
let navBarHNFS = GKDevice.navBarHeightNonFullScreen()
let navBarH = GKDevice.navBarHeight()
var frame = obj.frame
frame.origin.y = self.frame.size.height - (self.gk_nonFullScreen ? navBarHNFS : navBarH)
obj.frame = frame
}
}
}
}
// 重新设置透明度
let alpha = self.gk_navBarBackgroundAlpha
self.gk_navBarBackgroundAlpha = alpha
// 分割线处理
self.gk_navLineHideOrShow()
}
fileprivate func gk_navLineHideOrShow() {
guard let backgroundView = self.subviews.first else { return }
for view in backgroundView.subviews {
if view.frame.size.height > 0 && view.frame.size.height <= 1.0 {
view.isHidden = self.gk_navLineHidden
}
}
}
}
// 实现touches方法,防止其实现父试图的touches方法
extension GKNavigationBar {
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
open override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
}
open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
}
}
//
// GKNavigationInteractiveTransition.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/11/27.
// Copyright © 2020 QuintGao. All rights reserved.
//
import UIKit
class GKNavigationInteractiveTransition: NSObject {
var isGesturePush: Bool = false
var pushTransition: UIPercentDrivenInteractiveTransition?
var popTransition: UIPercentDrivenInteractiveTransition?
weak var navigationController: UINavigationController!
weak var visibleVC: UIViewController?
var systemTarget: Any?
var systemAction: Selector?
// MARK: - 滑动手势处理
@objc public func panGestureAction(_ gesture: UIPanGestureRecognizer) {
// 进度
guard let width = gesture.view?.bounds.size.width else { return }
if width == 0 { return }
var progress = gesture.translation(in: gesture.view).x / width
let velocity = gesture.velocity(in: gesture.view)
// 在手势开始的时候判断是push操作还是pop操作
if gesture.state == .began {
self.isGesturePush = velocity.x < 0 ? true : false
self.visibleVC = self.navigationController.visibleViewController
}
// push时progress < 0 需要做处理
if self.isGesturePush {
progress = -progress
}
progress = min(1.0, max(0.0, progress))
if gesture.state == .began {
if self.isGesturePush { // push
if self.navigationController.gk_openScrollLeftPush {
if let visibleVC = self.visibleVC {
if visibleVC.gk_pushDelegate != nil {
self.pushTransition = UIPercentDrivenInteractiveTransition()
visibleVC.gk_pushDelegate?.pushToNextViewController?()
}
}
}
pushScrollBegan()
}else { // pop
if self.navigationController.gk_transitionScale {
self.popTransition = UIPercentDrivenInteractiveTransition()
self.navigationController.popViewController(animated: true)
}else {
if let visibleVC = self.visibleVC {
if visibleVC.gk_systemGestureHandleDisabled {
var shouldPop = visibleVC.navigationShouldPop()
let selector = NSSelectorFromString("navigationShouldPopOnGesture")
if visibleVC.responds(to: selector) {
if visibleVC.perform(selector) != nil {
shouldPop = true
}else {
shouldPop = false
}
}
if shouldPop {
self.popTransition = UIPercentDrivenInteractiveTransition()
self.navigationController.popViewController(animated: true)
}
}
}
}
popScrollBegan()
}
}else if gesture.state == .changed {
if self.isGesturePush {
if self.pushTransition != nil {
self.pushTransition?.update(progress)
}
pushScrollUpdate(progress: progress)
}else {
if self.popTransition != nil {
self.popTransition?.update(progress)
}
popScrollUpdate(progress: progress)
}
}else if gesture.state == .ended || gesture.state == .cancelled {
if self.isGesturePush {
var pushFinished: Bool = progress > 0.5
if self.pushTransition != nil {
if GKConfigure.isVelocityInsensitivity(velocity.x) && velocity.x < 0 {
pushFinished = true
self.pushTransition?.finish()
}else {
if progress > GKConfigure.gk_pushTransitionCriticalValue {
pushFinished = true
self.pushTransition?.finish()
}else {
pushFinished = false
self.pushTransition?.cancel()
}
}
}
pushScrollEnded(finished: pushFinished)
}else {
var popFinished: Bool = progress > 0.5
if self.popTransition != nil {
if GKConfigure.isVelocityInsensitivity(velocity.x) && velocity.x > 0 {
popFinished = true
self.popTransition?.finish()
}else {
if progress > GKConfigure.gk_popTransitionCriticalValue {
popFinished = true
self.popTransition?.finish()
}else {
popFinished = false
self.popTransition?.cancel()
}
}
}
popScrollEnded(finished: popFinished)
}
self.pushTransition = nil
self.popTransition = nil
self.visibleVC = nil
self.isGesturePush = false
}
}
func pushScrollBegan() {
if let visibleVC = self.visibleVC {
visibleVC.gk_pushDelegate?.viewControllerPushScrollBegan?()
}
}
func pushScrollUpdate(progress: CGFloat) {
if let visibleVC = self.visibleVC {
visibleVC.gk_pushDelegate?.viewControllerPushScrollUpdate?(progress: progress)
}
}
func pushScrollEnded(finished: Bool) {
if let visibleVC = self.visibleVC {
visibleVC.gk_pushDelegate?.viewControllerPushScrollEnded?(finished: finished)
}
}
func popScrollBegan() {
if let visibleVC = self.visibleVC {
visibleVC.gk_popDelegate?.viewControllerPopScrollBegan?()
}
}
func popScrollUpdate(progress: CGFloat) {
if let visibleVC = self.visibleVC {
visibleVC.gk_popDelegate?.viewControllerPopScrollUpdate?(progress: progress)
}
}
func popScrollEnded(finished: Bool) {
if let visibleVC = self.visibleVC {
visibleVC.gk_popDelegate?.viewControllerPopScrollEnded?(finished: finished)
}
}
}
extension GKNavigationInteractiveTransition: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
if fromVC.gk_pushTransition != nil && operation == .push {
return fromVC.gk_pushTransition
}
if fromVC.gk_popTransition != nil && operation == .pop {
return fromVC.gk_popTransition
}
let isScale = self.navigationController.gk_transitionScale
if (isScale || self.pushTransition != nil) && operation == .push {
return GKPushAnimatedTransition(scale: isScale)
}
if (isScale || self.popTransition != nil) && operation == .pop {
return GKPopAnimatedTransition(scale: isScale)
}
return nil
}
func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
if self.pushTransition != nil && animationController.isKind(of: GKPushAnimatedTransition.self) {
return self.pushTransition
}
if self.popTransition != nil && animationController.isKind(of: GKPopAnimatedTransition.self) {
return self.popTransition
}
return nil
}
}
extension GKNavigationInteractiveTransition: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
// 不是UIPanGestureRecognizer,不作处理
if gestureRecognizer.isKind(of: UIPanGestureRecognizer.self) == false {
return true
}
// 转为UIPanGestureRecognizer
let panGesture = gestureRecognizer as! UIPanGestureRecognizer
// 如果没有visibleViewController,不作处理
guard let visibleVC = self.navigationController.visibleViewController else {
return true
}
// 当前VC禁止滑动返回
if visibleVC.gk_interactivePopDisabled {
return false
}
// 根据transition判断是左滑还是右滑
let transition = panGesture.translation(in: gestureRecognizer.view)
// 如果开启缩放,则移除系统处理
if self.navigationController.gk_transitionScale {
gestureRecognizer.removeTarget(self.systemTarget, action: self.systemAction)
}
if transition.x < 0 { // 左滑
// 开启了左滑push并设置了代理
if self.navigationController.gk_openScrollLeftPush && visibleVC.gk_pushDelegate != nil {
gestureRecognizer.removeTarget(self.systemTarget, action: self.systemAction)
}else {
return false
}
}else if (transition.x > 0) { // 右滑
if !visibleVC.gk_systemGestureHandleDisabled {
var shouldPop = visibleVC.navigationShouldPop()
let selector = NSSelectorFromString("navigationShouldPopOnGesture")
if visibleVC.responds(to: selector) {
if visibleVC.perform(selector) != nil {
shouldPop = true
}else {
shouldPop = false
}
}
if shouldPop == false { return false }
}
// 解决根控制器右滑时出现的卡死情况
if self.navigationController.viewControllers.count <= 1 { return false }
// 忽略超出手势区域
let beginningLocation = gestureRecognizer.location(in: gestureRecognizer.view)
let maxAllowDistance = visibleVC.gk_maxPopDistance
if maxAllowDistance > 0 && beginningLocation.x > maxAllowDistance { return false }
}else {
if visibleVC.gk_fullScreenPopDisabled {
// 修复边缘侧滑返回失效的bug
if self.navigationController.viewControllers.count <= 1 {
return false
}
}else {
// 修复全屏返回手势上下滑动时可能导致的卡死情况
return false
}
}
// 忽略导航控制器正在做转场动画
if self.navigationController.value(forKey: "_isTransitioning") as? Bool == true { return false }
return true
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
// 获取当前显示的VC
guard let visibleVC = navigationController.visibleViewController else { return false }
let selector = NSSelectorFromString("popGestureRecognizer:shouldRecognizeSimultaneouslyWith:")
if visibleVC.responds(to: selector) {
if visibleVC.perform(selector, with: gestureRecognizer, with: otherGestureRecognizer) != nil {
return true
}else {
return false
}
}
return false
}
}
//
// GKPopAnimatedTransition.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/3/24.
// Copyright © 2020 QuintGao. All rights reserved.
//
import UIKit
open class GKPopAnimatedTransition: GKBaseAnimatedTransition {
public override func animateTransition() {
// 是否隐藏tabBar
self.isHideTabBar = (self.toViewController.tabBarController != nil) && (self.fromViewController.hidesBottomBarWhenPushed == true) && (self.toViewController.gk_captureImage != nil)
if (self.toViewController.navigationController?.children.first != self.toViewController) {
self.isHideTabBar = false
}
let tabBar = self.toViewController.tabBarController?.tabBar
if (tabBar == nil) {
self.isHideTabBar = false
}
let screenW = self.containerView.bounds.size.width
let screenH = self.containerView.bounds.size.height
let toView = UIView(frame: self.containerView.bounds)
var captureView: UIView? = nil
toView.addSubview(self.toViewController.view)
if self.isHideTabBar {
captureView = UIImageView(image: self.toViewController.gk_captureImage!)
var frame = tabBar!.frame
frame.origin.x = 0
captureView?.frame = frame
toView.addSubview(captureView!)
tabBar?.isHidden = true
}
if self.isScale {
self.shadowView = UIView(frame: CGRect(x: 0, y: 0, width: screenW, height: screenH))
self.shadowView.backgroundColor = UIColor.black.withAlphaComponent(0.6)
toView.addSubview(self.shadowView)
toView.transform = CGAffineTransform(scaleX: GKConfigure.gk_scaleX, y: GKConfigure.gk_scaleY)
}else {
var frame = toView.frame
frame.origin.x = -0.3 * frame.size.width
toView.frame = frame
}
self.containerView.insertSubview(toView, belowSubview: self.fromViewController.view)
self.fromViewController.view.layer.shadowColor = UIColor.black.cgColor
self.fromViewController.view.layer.shadowOpacity = 0.15
self.fromViewController.view.layer.shadowRadius = 3.0
UIView.animate(withDuration: animationDuration(), animations: {
self.fromViewController.view.frame = CGRect(x: screenW, y: 0, width: screenW, height: screenH)
if self.isScale {
self.shadowView.backgroundColor = UIColor.black.withAlphaComponent(0)
toView.transform = .identity
}else {
var frame = toView.frame
frame.origin.x = 0
toView.frame = frame
}
}) { (finished) in
if self.isHideTabBar {
self.toViewController.gk_captureImage = nil
if (self.transitionContext.transitionWasCancelled) {
self.toViewController.view.removeFromSuperview()
}else {
self.containerView.addSubview(self.toViewController.view)
}
toView.transform = .identity
toView.removeFromSuperview()
if (captureView != nil) {
captureView?.removeFromSuperview()
captureView = nil
}
if (self.toViewController.navigationController?.children.count == 1) {
tabBar?.isHidden = false
}
}
if self.isScale {
self.shadowView.removeFromSuperview()
}
self.completeTransition()
}
}
}
//
// GKPushAnimatedTransition.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/3/24.
// Copyright © 2020 QuintGao. All rights reserved.
//
import UIKit
open class GKPushAnimatedTransition: GKBaseAnimatedTransition {
public override func animateTransition() {
// 解决UITabBarController左滑push时的显示问题
self.isHideTabBar = (self.fromViewController.tabBarController != nil) && (self.toViewController.hidesBottomBarWhenPushed == true)
let tabBar = self.fromViewController.tabBarController?.tabBar
if (tabBar == nil) {
self.isHideTabBar = false
}
// tabBar位置不对或隐藏
if (tabBar?.frame.origin.x != 0 || tabBar?.isHidden == true) {
self.isHideTabBar = false
}
// 非根控制器
if (self.fromViewController.navigationController?.children.first != self.fromViewController) {
self.isHideTabBar = false
}
let screenW = self.containerView.bounds.size.width
let screenH = self.containerView.bounds.size.height
let fromView = UIView(frame: self.containerView.bounds)
fromView.addSubview(fromViewController.view)
var captureView: UIView? = nil
if self.isHideTabBar {
// 截取tabBar
let captureImage = GKConfigure.getCapture(with: tabBar!)
self.fromViewController.gk_captureImage = captureImage
captureView = UIImageView(image: captureImage)
var frame = tabBar!.frame;
frame.origin.x = 0
captureView?.frame = frame
fromView.addSubview(captureView!)
tabBar?.isHidden = true
}
if self.isScale {
self.shadowView = UIView(frame: CGRect(x: 0, y: 0, width: screenW, height: screenH))
self.shadowView.backgroundColor = UIColor.black.withAlphaComponent(0)
fromView.addSubview(self.shadowView)
fromView.transform = .identity
}
self.containerView.addSubview(fromView)
// 设置toViewController
self.toViewController.view.frame = CGRect(x: screenW, y: 0, width: screenW, height: screenH)
self.toViewController.view.layer.shadowColor = UIColor.black.cgColor
self.toViewController.view.layer.shadowOpacity = 0.15
self.toViewController.view.layer.shadowRadius = 3.0
self.containerView.addSubview(self.toViewController.view)
UIView.animate(withDuration: animationDuration(), animations: {
if self.isScale {
self.shadowView.backgroundColor = UIColor.black.withAlphaComponent(0.6)
fromView.transform = CGAffineTransform(scaleX: GKConfigure.gk_scaleX, y: GKConfigure.gk_scaleY)
}else {
var frame = fromView.frame
frame.origin.x = -0.3 * frame.size.width
fromView.frame = frame
}
self.toViewController.view.frame = CGRect(x: 0, y: 0, width: screenW, height: screenH)
}) { (finished) in
if self.isHideTabBar {
if (self.transitionContext.transitionWasCancelled) {
self.containerView.addSubview(self.fromViewController.view)
}else {
self.fromViewController.view.removeFromSuperview()
}
fromView.transform = .identity
fromView.removeFromSuperview()
if (captureView != nil) {
captureView?.removeFromSuperview()
captureView = nil
}
}
if self.isScale {
self.shadowView.removeFromSuperview()
}
self.completeTransition()
}
}
}
//
// UIBarButtonItem+GKExtension.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/3/25.
// Copyright © 2020 QuintGao. All rights reserved.
//
import UIKit
extension UIBarButtonItem {
public class func gk_item(title: String?, target: Any, action: Selector) -> UIBarButtonItem {
gk_item(title: title, image: nil, target: target, action: action)
}
public class func gk_item(title: String?, font: UIFont?, target: Any, action: Selector) -> UIBarButtonItem {
gk_item(title: title, color: nil, font: font, target: target, action: action)
}
public class func gk_item(title: String?, color: UIColor?, target: Any, action: Selector) -> UIBarButtonItem {
gk_item(title: title, color: color, font: nil, target: target, action: action)
}
public class func gk_item(title: String?, color: UIColor?, font: UIFont?, target: Any, action: Selector) -> UIBarButtonItem {
gk_item(title: title, titleColor: color, font: font, image: nil, imageColor: nil, highLightImage: nil, target: target, action: action)
}
public class func gk_item(image: UIImage?, target: Any, action: Selector) -> UIBarButtonItem {
gk_item(title: nil, image: image, target: target, action: action)
}
public class func gk_item(image: UIImage?, color: UIColor?, target: Any, action: Selector) -> UIBarButtonItem {
gk_item(title: nil, titleColor: nil, font: nil, image: image, imageColor: color, highLightImage: nil, target: target, action: action)
}
public class func gk_item(image: UIImage?, highLightImage: UIImage?, target: Any, action: Selector) -> UIBarButtonItem {
gk_item(title: nil, titleColor: nil, font: nil, image: image, imageColor: nil, highLightImage: highLightImage, target: target, action: action)
}
public class func gk_item(title: String?, image: UIImage?, target: Any, action: Selector) -> UIBarButtonItem {
gk_item(title: title, titleColor: nil, font: nil, image: image, imageColor: nil, highLightImage: nil, target: target, action: action)
}
public class func gk_item(title: String?, titleColor: UIColor?, font: UIFont?, image: UIImage?, imageColor: UIColor?, highLightImage: UIImage?, target: Any, action: Selector) -> UIBarButtonItem {
let button = UIButton()
if let title = title {
button.setTitle(title, for: .normal)
}
if let titleColor = titleColor {
button.setTitleColor(titleColor, for: .normal)
}
if let font = font {
button.titleLabel?.font = font
}
var buttonImage = image
if let image = image, let imageColor = imageColor {
buttonImage = UIImage.gk_change(with: image, color: imageColor)
}
if let buttonImage = buttonImage {
button.setImage(buttonImage, for: .normal)
}
if let highLightImage = highLightImage {
button.setImage(highLightImage, for: .highlighted)
}
button.sizeToFit()
if button.bounds.size.width < 44.0 {
button.bounds = CGRect(x: 0, y: 0, width: 44.0, height: 44.0)
}
button.addTarget(target, action: action, for: .touchUpInside)
return UIBarButtonItem(customView: button)
}
}
//
// UIImage+GKExtension.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/3/25.
// Copyright © 2020 QuintGao. All rights reserved.
//
import UIKit
extension UIImage {
public class func gk_image(with name: String) -> UIImage? {
var image: UIImage?
if let bundle = Bundle.gk_bundle {
image = UIImage(named: name, in: bundle, compatibleWith: nil)
}
if image == nil {
image = UIImage(named: name)
}
return image
}
public class func gk_image(with color: UIColor) -> UIImage? {
return self.gk_image(with: color, size: CGSize(width: 1, height: 1))
}
public class func gk_image(with color: UIColor, size: CGSize) -> UIImage? {
if size.width <= 0 || size.height <= 0 { return nil }
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
UIGraphicsBeginImageContext(size)
guard let context = UIGraphicsGetCurrentContext() else { return nil }
context.setFillColor(color.cgColor)
context.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
public class func gk_change(with image: UIImage?, color: UIColor) -> UIImage? {
guard let image = image else { return nil }
if image.size.width <= 0 || image.size.height <= 0 { return nil }
let drawRect = CGRectMake(0, 0, image.size.width, image.size.height)
UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
guard let context = UIGraphicsGetCurrentContext() else { return nil }
context.setBlendMode(.normal)
context.clip(to: drawRect, mask: image.cgImage!)
color.setFill()
context.fill(drawRect)
guard let resultImage = UIGraphicsGetImageFromCurrentImageContext() else { return nil }
UIGraphicsEndImageContext()
return resultImage
}
}
//
// UINavigationController+GKExtension.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/3/25.
// Copyright © 2020 QuintGao. All rights reserved.
//
import UIKit
extension UINavigationController: GKChildAwakeProtocol {
// MARK: - 重新系统方法
private static let onceToken = UUID().uuidString
public static func gkChildAwake() {
DispatchQueue.once(token: onceToken) {
gk_swizzled_instanceMethod("gkNav", oldClass: self, oldSelector: "pushViewController:animated:", newClass: self)
}
}
@objc func gkNav_pushViewController(_ viewController: UIViewController, animated: Bool) {
if self.gk_openSystemNavHandle {
self.isNavigationBarHidden = true
}
gkNav_pushViewController(viewController, animated: animated)
}
}
extension UINavigationController {
fileprivate struct AssociatedKeys {
static var gkOpenSystemNavHandle: Void?
static var gkHideNavigationBar: Void?
}
public var gk_openSystemNavHandle: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkOpenSystemNavHandle) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkOpenSystemNavHandle, newValue)
}
}
public var gk_hideNavigationBar: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkHideNavigationBar) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkHideNavigationBar, newValue)
}
}
}
//
// UINavigationController+GKGesture.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2022/3/18.
// Copyright © 2022 QuintGao. All rights reserved.
//
import UIKit
extension UINavigationController {
// 创建便利构造函数为UINavigationcontroller增加初始化方法
public convenience init(rootVC: UIViewController) {
self.init()
gk_openGestureHandle = true
gk_transitionScale = false
pushViewController(rootVC, animated: true)
}
public convenience init(rootVC: UIViewController, scale: Bool) {
self.init()
gk_openGestureHandle = true
gk_transitionScale = scale
pushViewController(rootVC, animated: true)
}
}
extension UINavigationController: GKGestureChildAwakeProtocol {
// MARK: - 重新系统方法
private static let onceToken = UUID().uuidString
public static func gkGestureChildAwake() {
DispatchQueue.once(token: onceToken) {
let oriSels = ["viewDidLoad",
"pushViewController:animated:",
"navigationBar:shouldPopItem:"
]
for oriSel in oriSels {
gk_swizzled_instanceMethod("gkNavGesture", oldClass: self, oldSelector: oriSel, newClass: self)
}
}
}
@objc func gkNavGesture_viewDidLoad() {
if self.gk_openGestureHandle {
if self.isKind(of: UIImagePickerController.self) {
return
}
if self.isKind(of: UIVideoEditorController.self) {
return
}
// 设置背景色
self.view.backgroundColor = UIColor.black
// 设置代理
self.delegate = self.interactiveTransition
self.interactivePopGestureRecognizer?.isEnabled = false
// 注册控制器属性改变通知
NotificationCenter.default.addObserver(self, selector: #selector(propertyChangeNotification(_:)), name: GKViewControllerPropertyChanged, object: nil)
}
gkNavGesture_viewDidLoad()
}
@objc func gkNavGesture_pushViewController(_ viewController: UIViewController, animated: Bool) {
if self.children.count > 0 {
let rootVC = self.children.first!
// 获取tabbar截图
if viewController.gk_systemGestureHandleDisabled && rootVC.gk_captureImage == nil {
rootVC.gk_captureImage = GKConfigure.getCapture(with: rootVC.view.window ?? rootVC.view)
}
// 设置push时是否隐藏tabbar
if GKConfigure.gk_hidesBottomBarWhenPushed && rootVC != viewController {
viewController.hidesBottomBarWhenPushed = true
}
}
gkNavGesture_pushViewController(viewController, animated: animated)
}
// source:https://github.com/onegray/UIViewController-BackButtonHandler
@objc func gkNavGesture_navigationBar(_ navigationBar: UINavigationBar, shouldPopItem: UINavigationItem) -> Bool {
if self.viewControllers.count < navigationBar.items?.count ?? 0 {
return true
}
var shouldPop = self.topViewController?.navigationShouldPop()
let selector = NSSelectorFromString("navigationShouldPopOnClick")
if let vc = self.topViewController, vc.responds(to: selector) {
if vc.perform(selector) != nil {
shouldPop = true
}else {
shouldPop = false
}
}
if shouldPop == true {
DispatchQueue.main.async { [self] in
popViewController(animated: true)
}
}else {
// Workaround for iOS7.1. Thanks to @boliva - http://stackoverflow.com/posts/comments/34452906
for subview in navigationBar.subviews {
if 0.0 < subview.alpha && subview.alpha < 1.0 {
UIView.animate(withDuration: 0.25) {
subview.alpha = 1.0
}
}
}
}
return false
}
@objc func propertyChangeNotification(_ notify: Notification) {
guard let obj = notify.object as? [String: Any] else { return }
let vc: UIViewController = obj["viewController"] as! UIViewController
// 不处理导航控制器和tabbar控制器
if vc.isKind(of: UINavigationController.self) { return }
if vc.isKind(of: UITabBarController.self) { return }
if vc.navigationController == nil { return }
if vc.navigationController != self { return }
// 修复非导航控制器子类时出现的问题
if vc.parent != self { return }
var exist = false
if let shiledVCs = GKConfigure.shiledGuestureVCs {
for obj in shiledVCs {
if obj is UIViewController.Type {
if vc.isKind(of: obj as! UIViewController.Type) {
exist = true
}
}else if obj is String {
if let cls = NSStringFromClass(vc.classForCoder).components(separatedBy: ".").last, let str = obj as? String {
if cls == str {
exist = true
}else if cls.contains(str) {
exist = true
}
}
}
}
}
if exist { return }
// 手势处理
if vc.gk_interactivePopDisabled { // 禁止滑动
self.view.removeGestureRecognizer(self.screenPanGesture)
self.view.removeGestureRecognizer(self.panGesture)
}else if vc.gk_fullScreenPopDisabled { // 禁止全屏滑动,支持边缘滑动
self.view.removeGestureRecognizer(self.panGesture)
self.view.addGestureRecognizer(self.screenPanGesture)
if vc.gk_systemGestureHandleDisabled {
self.screenPanGesture.removeTarget(self.systemTarget, action: self.systemAction)
}else {
self.screenPanGesture.addTarget(self.systemTarget!, action: self.systemAction)
}
}else { // 支持全屏滑动
self.view.removeGestureRecognizer(self.screenPanGesture)
self.view.addGestureRecognizer(self.panGesture)
if vc.gk_systemGestureHandleDisabled {
self.panGesture.removeTarget(self.systemTarget, action: self.systemAction)
}else {
self.panGesture.addTarget(self.systemTarget!, action: self.systemAction)
}
}
}
}
extension UINavigationController {
fileprivate struct AssociatedKeys {
static var gkTransitionScale: Void?
static var gkOpenScrollLeftPush: Void?
static var gkOpenGestureHandle: Void?
static var screenPanGesture: Void?
static var panGesture: Void?
static var transition: Void?
}
public var gk_transitionScale: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkTransitionScale) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkTransitionScale, newValue)
}
}
public var gk_openScrollLeftPush: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkOpenScrollLeftPush) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkOpenScrollLeftPush, newValue)
}
}
fileprivate var gk_openGestureHandle: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkOpenGestureHandle) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkOpenGestureHandle, newValue)
}
}
var screenPanGesture: UIScreenEdgePanGestureRecognizer {
get {
var panGesture = gk_getAssociatedObject(self, &AssociatedKeys.screenPanGesture) as? UIScreenEdgePanGestureRecognizer
if panGesture == nil {
panGesture = UIScreenEdgePanGestureRecognizer(target: self.interactiveTransition, action:#selector(self.interactiveTransition.panGestureAction(_:)))
panGesture?.edges = .left
panGesture?.delegate = self.interactiveTransition
gk_setAssociatedObject(self, &AssociatedKeys.screenPanGesture, panGesture)
}
return panGesture!
}
}
var panGesture: UIPanGestureRecognizer {
get {
var panGesture = gk_getAssociatedObject(self, &AssociatedKeys.panGesture) as? UIPanGestureRecognizer
if panGesture == nil {
panGesture = UIPanGestureRecognizer(target: self.interactiveTransition, action: #selector(self.interactiveTransition.panGestureAction(_:)))
panGesture?.maximumNumberOfTouches = 1
panGesture?.delegate = self.interactiveTransition
gk_setAssociatedObject(self, &AssociatedKeys.panGesture, panGesture)
}
return panGesture!
}
}
var interactiveTransition: GKNavigationInteractiveTransition {
get {
var transition = gk_getAssociatedObject(self, &AssociatedKeys.transition) as? GKNavigationInteractiveTransition
if transition == nil {
transition = GKNavigationInteractiveTransition()
transition?.navigationController = self
transition?.systemTarget = self.systemTarget
transition?.systemAction = self.systemAction
gk_setAssociatedObject(self, &AssociatedKeys.transition, transition)
}
return transition!
}
}
var systemTarget: Any? {
get {
let internalTargets = self.interactivePopGestureRecognizer?.value(forKey: "targets") as? [AnyObject]
let internamTarget = internalTargets?.first?.value(forKey: "target")
return internamTarget
}
}
var systemAction: Selector {
return NSSelectorFromString("handleNavigationTransition:")
}
}
extension UINavigationController {
open override var childForStatusBarHidden: UIViewController? {
return topViewController
}
open override var childForStatusBarStyle: UIViewController? {
return topViewController
}
}
//
// UINavigationItem+GKExtension.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/3/25.
// Copyright © 2020 QuintGao. All rights reserved.
//
import UIKit
extension UINavigationItem: GKAwakeProtocol {
// MARK: - 重新系统方法
private static let onceToken = UUID().uuidString
@objc public static func gkAwake() {
DispatchQueue.once(token: onceToken) {
if #available(iOS 11.0, *) {} else {
let oriSels = ["setLeftBarButtonItem:animated:",
"setLeftBarButtonItems:animated:",
"setRightBarButtonItem:animated:",
"setRightBarButtonItems:animated:"]
for oriSel in oriSels {
gk_swizzled_instanceMethod("gk", oldClass: self, oldSelector: oriSel, newClass: self)
}
}
}
}
@objc func gk_setLeftBarButtonItem(_ item: UIBarButtonItem?, animated: Bool) {
if !GKConfigure.fixNavItemSpaceDisabled() && item != nil { // 存在按钮且需要调节
self.setLeftBarButtonItems([item!], animated: animated)
}else { // 不存在按钮或者不需要调节
self.setLeftBarButtonItems(nil, animated: false)
self.gk_setLeftBarButtonItem(item, animated: animated)
}
}
@objc func gk_setLeftBarButtonItems(_ items: [UIBarButtonItem]?, animated: Bool) {
guard var leftItems = items else { return }
if !GKConfigure.fixNavItemSpaceDisabled() && leftItems.count > 0 {
let firstItem = leftItems.first!
let width = GKConfigure.gk_navItemLeftSpace - GKConfigure.gk_fixedSpace()
if firstItem.width == width {
self.gk_setLeftBarButtonItems(leftItems, animated: animated)
}else {
leftItems.insert(fixedSpace(width), at: 0)
self.gk_setLeftBarButtonItems(leftItems, animated: animated)
}
}else {
self.gk_setLeftBarButtonItems(leftItems, animated: animated)
}
}
@objc func gk_setRightBarButtonItem(_ item: UIBarButtonItem?, animated: Bool) {
if !GKConfigure.fixNavItemSpaceDisabled() && item != nil {
self.setRightBarButtonItems([item!], animated: animated)
}else {
self.setRightBarButtonItems(nil, animated: false)
self.gk_setRightBarButtonItem(item, animated: animated)
}
}
@objc func gk_setRightBarButtonItems(_ items: [UIBarButtonItem]?, animated: Bool) {
guard var rightItems = items else { return }
if !GKConfigure.fixNavItemSpaceDisabled() && rightItems.count > 0 {
let firstItem = rightItems.first!
let width = GKConfigure.gk_navItemRightSpace - GKConfigure.gk_fixedSpace()
if firstItem.width == width {
self.gk_setRightBarButtonItems(items, animated: animated)
}else {
rightItems.insert(fixedSpace(width), at: 0)
self.gk_setRightBarButtonItems(rightItems, animated: animated)
}
}else {
self.gk_setRightBarButtonItems(rightItems, animated: animated);
}
}
fileprivate func fixedSpace(_ width: CGFloat) -> UIBarButtonItem {
let fixedItem = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
fixedItem.width = width
return fixedItem
}
}
extension NSObject: GKObjectAwakeProtocol {
// MARK: - 重新系统方法
private static let onceToken = UUID().uuidString
public static func gkObjectAwake() {
DispatchQueue.once(token: onceToken) {
if #available(iOS 11.0, *) {
let oriSels = ["_UINavigationBarContentView": "layoutSubviews", "_UINavigationBarContentViewLayout": "_updateMarginConstraints"]
for (cls, sel) in oriSels {
gk_swizzled_instanceMethod("gk", oldClass: NSClassFromString(cls), oldSelector: sel, newClass: NSObject.self)
}
}
}
}
@objc func gk_layoutSubviews() {
gk_layoutSubviews()
if GKConfigure.fixNavItemSpaceDisabled() { return }
if let cls = NSClassFromString("_UINavigationBarContentView") {
if !self.isMember(of: cls) { return }
guard let layout = self.value(forKey: "_layout") as? NSObject else { return }
let selector = NSSelectorFromString("_updateMarginConstraints")
if layout.responds(to: selector) {
layout.perform(selector)
}
}
}
@objc func gk__updateMarginConstraints() {
gk__updateMarginConstraints()
if GKConfigure.fixNavItemSpaceDisabled() { return }
if let cls = NSClassFromString("_UINavigationBarContentViewLayout") {
if !self.isMember(of: cls) { return }
gk_adjustLeadingBarConstraints()
gk_adjustTrailingBarConstraints()
}
}
fileprivate func gk_adjustLeadingBarConstraints() {
if GKConfigure.fixNavItemSpaceDisabled() { return }
let leadingBarConstrainst: [NSLayoutConstraint]? = self.value(forKey: "_leadingBarConstraints") as? [NSLayoutConstraint]
if leadingBarConstrainst == nil { return }
let constant = GKConfigure.gk_navItemLeftSpace - GKConfigure.gk_fixedSpace()
for constraint in leadingBarConstrainst! {
if constraint.firstAttribute == .leading && constraint.secondAttribute == .leading {
constraint.constant = constant
}
}
}
fileprivate func gk_adjustTrailingBarConstraints() {
if GKConfigure.fixNavItemSpaceDisabled() { return }
let trailingBarConstraints: [NSLayoutConstraint]? = self.value(forKey: "_trailingBarConstraints") as? [NSLayoutConstraint]
if trailingBarConstraints == nil { return }
let constant = GKConfigure.gk_fixedSpace() - GKConfigure.gk_navItemRightSpace
for constraint in trailingBarConstraints! {
if constraint.firstAttribute == .trailing && constraint.secondAttribute == .trailing {
constraint.constant = constant
}
}
}
}
//
// UIScrollView+GKExtension.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/3/25.
// Copyright © 2020 QuintGao. All rights reserved.
//
import UIKit
extension UIScrollView: GKAwakeProtocol {
fileprivate struct AssociatedKeys {
static var gkOpenGestureHandle: Void?
}
/// 是否开启UIScrollView左滑返回手势处理,默认NO
public var gk_openGestureHandle: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkOpenGestureHandle) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkOpenGestureHandle, newValue)
}
}
// MARK: - 重新系统方法
private static let onceToken = UUID().uuidString
@objc public static func gkAwake() {
DispatchQueue.once(token: onceToken) {
let oriSels = ["willMoveToSuperview:"]
for oriSel in oriSels {
gk_swizzled_instanceMethod("gkGesture", oldClass: self, oldSelector: oriSel, newClass: self)
}
}
}
@objc func gkGesture_willMove(toSuperview newSuperview: UIView?) {
if (newSuperview != nil), GKConfigure.gk_openScrollViewGestureHandle {
self.gk_openGestureHandle = true
}
gkGesture_willMove(toSuperview: newSuperview)
}
}
extension UIScrollView {
open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if !self.gk_openGestureHandle {
return true
}
if self.panBack(gesture: gestureRecognizer) {
return false
}
return true
}
fileprivate func panBack(gesture: UIGestureRecognizer) -> Bool {
if gesture == self.panGestureRecognizer {
let point = self.panGestureRecognizer.translation(in: self)
let state = gesture.state
// 设置手势滑动的位置距离屏幕左边的区域
let locationDistance = UIScreen.main.bounds.size.width
if state == .began || state == .possible {
let location = gesture.location(in: self)
if point.x > 0 && location.x < locationDistance && contentOffset.x <= 0 {
return true
}
}
}
return false
}
}
//
// UIViewController+GKExtension.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2020/3/25.
// Copyright © 2020 QuintGao. All rights reserved.
//
import UIKit
extension UIViewController: GKAwakeProtocol {
fileprivate struct AssociatedKeys {
static var gkNavBarAlpha: Void?
static var gkNavBarInit: Void?
static var gkNavBarAdded: Void?
static var gkNavigationBar: Void?
static var gkNavigationItem: Void?
static var gkStatusBarHidden: Void?
static var gkStatusBarStyle: Void?
static var gkBackImage: Void?
static var gkDarkBackImage: Void?
static var gkBlackBackImage: Void?
static var gkWhiteBackImage: Void?
static var gkBackStyle: Void?
static var gkNavBackgroundColor: Void?
static var gkNavBackgroundImage: Void?
static var gkDarkNavBackgroundImage: Void?
static var gkNavShadowColor: Void?
static var gkNavShadowImage: Void?
static var gkDarkNavShadowImage: Void?
static var gkNavLineHidden: Void?
static var gkNavTitle: Void?
static var gkNavTitleView: Void?
static var gkNavTitleColor: Void?
static var gkNavTitleFont: Void?
static var gkNavLeftBarButtonItem: Void?
static var gkNavLeftBarButtonItems: Void?
static var gkNavRightBarButtonItem: Void?
static var gkNavRightBarButtonItems: Void?
static var gkDisableFixNavItemSpace: Void?
static var gkOpenFixNavItemSpace: Void?
static var gkNavItemLeftSpace: Void?
static var gkNavItemRightSpace: Void?
}
public var gk_navBarAlpha: CGFloat {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkNavBarAlpha) as? CGFloat else { return 1 }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavBarAlpha, newValue)
self.gk_navigationBar.gk_navBarBackgroundAlpha = newValue
}
}
fileprivate var gk_navBarInit: Bool {
get {
guard let isInit = gk_getAssociatedObject(self, &AssociatedKeys.gkNavBarInit) as? Bool else { return false }
return isInit
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavBarInit, newValue)
}
}
fileprivate var gk_navBarAdded: Bool {
get {
guard let added = gk_getAssociatedObject(self, &AssociatedKeys.gkNavBarAdded) as? Bool else { return false }
return added
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavBarAdded, newValue)
}
}
public var gk_navigationBar: GKNavigationBar {
get {
var navigationBar = gk_getAssociatedObject(self, &AssociatedKeys.gkNavigationBar) as? GKNavigationBar
if navigationBar == nil {
navigationBar = GKNavigationBar()
self.gk_navBarInit = true
self.gk_navigationBar = navigationBar!
}
if self.isViewLoaded && !self.gk_navBarAdded {
self.view.addSubview(navigationBar!)
self.gk_navBarAdded = true
}
return navigationBar!
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavigationBar, newValue)
self.gk_disableFixNavItemSpace = GKConfigure.disableFixSpace
self.gk_openFixNavItemSpace = true
setupNavBarAppearance()
setupNavBarFrame()
}
}
public var gk_navigationItem: UINavigationItem {
get {
var item = gk_getAssociatedObject(self, &AssociatedKeys.gkNavigationItem) as? UINavigationItem
if item == nil {
item = UINavigationItem()
self.gk_navigationItem = item!
}
return item!
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavigationItem, newValue)
self.gk_navigationBar.items = [newValue]
}
}
public var gk_statusBarHidden: Bool {
get {
guard let isHidden = gk_getAssociatedObject(self, &AssociatedKeys.gkStatusBarHidden) as? Bool else { return false }
return isHidden
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkStatusBarHidden, newValue)
setNeedsStatusBarAppearanceUpdate()
}
}
public var gk_statusBarStyle: UIStatusBarStyle {
get {
guard let style = gk_getAssociatedObject(self, &AssociatedKeys.gkStatusBarStyle) as? UIStatusBarStyle else { return GKConfigure.statusBarStyle }
return style
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkStatusBarStyle, newValue)
setNeedsStatusBarAppearanceUpdate()
}
}
public var gk_backImage: UIImage? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkBackImage) as? UIImage
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkBackImage, newValue)
setBackItemImage(image: newValue)
}
}
public var gk_darkBackImage: UIImage? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkDarkBackImage) as? UIImage
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkDarkBackImage, newValue)
if #available(iOS 12.0, *) {
if traitCollection.userInterfaceStyle == .dark {
setBackItemImage(image: newValue)
}
}
}
}
public var gk_blackBackImage: UIImage? {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkBlackBackImage) else { return GKConfigure.blackBackImage }
return obj as? UIImage
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkBlackBackImage, newValue)
setBackItemImage(image: newValue)
}
}
public var gk_whiteBackImage: UIImage? {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkWhiteBackImage) else { return GKConfigure.whiteBackImage }
return obj as? UIImage
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkWhiteBackImage, newValue)
setBackItemImage(image: newValue)
}
}
public var gk_backStyle: GKNavigationBarBackStyle {
get {
guard let style = gk_getAssociatedObject(self, &AssociatedKeys.gkBackStyle) as? GKNavigationBarBackStyle else { return .none }
return style
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkBackStyle, newValue)
setBackItemImage(image: self.gk_backImage)
}
}
public var gk_navBackgroundColor: UIColor? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkNavBackgroundColor) as? UIColor
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavBackgroundColor, newValue)
setNavBackground(newValue)
}
}
public var gk_navBackgroundImage: UIImage? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkNavBackgroundImage) as? UIImage
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavBackgroundImage, newValue)
setNavBackground(newValue)
}
}
public var gk_darkNavBackgroundImage: UIImage? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkDarkNavBackgroundImage) as? UIImage
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkDarkNavBackgroundImage, newValue)
if #available(iOS 12.0, *) {
if traitCollection.userInterfaceStyle == .dark {
setNavBackground(newValue)
}
}
}
}
public var gk_navShadowColor: UIColor? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkNavShadowColor) as? UIColor
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavShadowColor, newValue)
setNavShadow(newValue)
}
}
public var gk_navShadowImage: UIImage? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkNavShadowImage) as? UIImage
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavShadowImage, newValue)
setNavShadow(newValue)
}
}
public var gk_darkNavShadowImage: UIImage? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkDarkNavShadowImage) as? UIImage
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkDarkNavShadowImage, newValue)
if #available(iOS 12.0, *) {
if traitCollection.userInterfaceStyle == .dark {
setNavShadow(newValue)
}
}
}
}
public var gk_navLineHidden: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkNavLineHidden) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavLineHidden, newValue)
self.gk_navigationBar.gk_navLineHidden = newValue
if #available(iOS 11.0, *) {
var shadowImage: UIImage?
if newValue {
shadowImage = UIImage()
}else if self.gk_navShadowImage != nil {
shadowImage = self.gk_navShadowImage
}else if self.gk_navShadowColor != nil {
shadowImage = UIImage.gk_change(with: UIImage.gk_image(with: "nav_line"), color: self.gk_navShadowColor!)
}
setNavShadow(shadowImage, color: nil)
}
self.gk_navigationBar.layoutSubviews()
}
}
public var gk_navTitle: String? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkNavTitle) as? String
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavTitle, newValue)
self.gk_navigationItem.title = newValue
}
}
public var gk_navTitleView: UIView? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkNavTitleView) as? UIView
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavTitleView, newValue)
self.gk_navigationItem.titleView = newValue
}
}
public var gk_navTitleColor: UIColor? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkNavTitleColor) as? UIColor
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavTitleColor, newValue)
setNavTitle(newValue)
}
}
public var gk_navTitleFont: UIFont? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkNavTitleFont) as? UIFont
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavTitleFont, newValue)
setNavTitle(newValue)
}
}
public var gk_navLeftBarButtonItem: UIBarButtonItem? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkNavLeftBarButtonItem) as? UIBarButtonItem
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavLeftBarButtonItem, newValue)
self.gk_navigationItem.leftBarButtonItem = newValue
}
}
public var gk_navLeftBarButtonItems: [UIBarButtonItem]? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkNavLeftBarButtonItems) as? [UIBarButtonItem]
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavLeftBarButtonItems, newValue)
self.gk_navigationItem.leftBarButtonItems = newValue
}
}
public var gk_navRightBarButtonItem: UIBarButtonItem? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkNavRightBarButtonItem) as? UIBarButtonItem
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavRightBarButtonItem, newValue)
self.gk_navigationItem.rightBarButtonItem = newValue
}
}
public var gk_navRightBarButtonItems: [UIBarButtonItem]? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkNavRightBarButtonItems) as? [UIBarButtonItem]
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavRightBarButtonItems, newValue)
self.gk_navigationItem.rightBarButtonItems = newValue
}
}
public var gk_disableFixNavItemSpace: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkDisableFixNavItemSpace) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkDisableFixNavItemSpace, newValue)
if GKConfigure.gk_disableFixSpace == newValue { return }
GKConfigure.update { configure in
configure.gk_disableFixSpace = newValue
}
}
}
public var gk_openFixNavItemSpace: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkOpenFixNavItemSpace) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkOpenFixNavItemSpace, newValue)
if GKConfigure.gk_openSystemFixSpace == newValue { return }
GKConfigure.update { configure in
configure.gk_openSystemFixSpace = newValue
}
}
}
public var gk_navItemLeftSpace: CGFloat {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkNavItemLeftSpace) as? CGFloat else { return GKNavigationBarItemSpace }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavItemLeftSpace, newValue)
if newValue == GKNavigationBarItemSpace { return }
GKConfigure.update { (configure) in
configure.gk_navItemLeftSpace = newValue
}
}
}
public var gk_navItemRightSpace: CGFloat {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkNavItemRightSpace) as? CGFloat else { return GKNavigationBarItemSpace }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkNavItemRightSpace, newValue)
if newValue == GKNavigationBarItemSpace { return }
GKConfigure.update { (configure) in
configure.gk_navItemRightSpace = newValue
}
}
}
}
extension UIViewController {
// MARK: - 重新系统方法
private static let onceToken = UUID().uuidString
@objc public static func gkAwake() {
DispatchQueue.once(token: onceToken) {
let oriSels = ["viewDidLoad",
"viewWillAppear:",
"viewDidAppear:",
"viewWillLayoutSubviews",
"traitCollectionDidChange:"]
for oriSel in oriSels {
gk_swizzled_instanceMethod("gk", oldClass: self, oldSelector: oriSel, newClass: self)
}
}
}
@objc func gk_viewDidLoad() {
// 设置默认状态
if let nav = self.navigationController, nav == self.parent {
self.gk_disableFixNavItemSpace = true
self.gk_openFixNavItemSpace = false
}
if shouldHandleNavBar() {
// 设置默认导航栏间距
self.gk_navItemLeftSpace = GKNavigationBarItemSpace
self.gk_navItemRightSpace = GKNavigationBarItemSpace
}
// 如果是根控制器,取消返回按钮
if let nav = self.navigationController, nav.children.count <= 1 {
if !self.gk_navBarInit { return }
self.gk_navLeftBarButtonItem = nil
}
gk_viewDidLoad()
}
@objc func gk_viewWillAppear(_ animated: Bool) {
if self.isKind(of: UINavigationController.self) { return }
if self.isKind(of: UITabBarController.self) { return }
if self.isKind(of: UIImagePickerController.self) { return }
if self.isKind(of: UIVideoEditorController.self) { return }
if self.isKind(of: UIAlertController.self) { return }
if NSStringFromClass(self.classForCoder).components(separatedBy: ".").last == "PUPhotoPickerHostViewController" { return }
if self.navigationController == nil { return }
if self.gk_navBarInit {
let disableFixNavItemSpace = self.gk_disableFixNavItemSpace
let openFixNavItemSpace = self.gk_openFixNavItemSpace
self.gk_disableFixNavItemSpace = disableFixNavItemSpace
self.gk_openFixNavItemSpace = openFixNavItemSpace
// 隐藏系统导航栏
if self.navigationController?.gk_openSystemNavHandle == false {
hiddenSystemNavBar()
}
// 将自定义的导航栏放置顶层
if !self.gk_navigationBar.isHidden {
self.view.bringSubviewToFront(self.gk_navigationBar)
}
}else {
if let nav = self.navigationController, nav == self.parent, !nav.isNavigationBarHidden, !isNonFullScreen() {
self.gk_disableFixNavItemSpace = self.gk_disableFixNavItemSpace
self.gk_openFixNavItemSpace = self.gk_openFixNavItemSpace
}
restoreSystemNavBar()
}
// 当创建了gk_navigationBar或者父控制器是导航控制器的时候才去调整导航栏间距
if self.shouldFixItemSpace() {
// 每次控制器出现的时候重置导航栏间距
if self.gk_navItemLeftSpace == GKNavigationBarItemSpace {
self.gk_navItemLeftSpace = GKConfigure.navItemLeftSpace
}else {
GKConfigure.update { configure in
configure.gk_navItemLeftSpace = self.gk_navItemLeftSpace
}
}
if self.gk_navItemRightSpace == GKNavigationBarItemSpace {
self.gk_navItemRightSpace = GKConfigure.navItemRightSpace
}else {
GKConfigure.update { configure in
configure.gk_navItemRightSpace = self.gk_navItemRightSpace
}
}
}
gk_viewWillAppear(animated)
}
@objc func gk_viewDidAppear(_ animated: Bool) {
if self.gk_navBarInit {
hiddenSystemNavBar()
}else {
restoreSystemNavBar()
}
gk_viewDidAppear(animated)
}
@objc func gk_viewWillLayoutSubviews() {
if self.gk_navBarInit {
setupNavBarFrame()
}
gk_viewWillLayoutSubviews()
}
@objc func gk_traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
if #available(iOS 13.0, *) {
if self.traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
if self.isKind(of: UINavigationController.self) { return }
if self.isKind(of: UITabBarController.self) { return }
if !self.gk_navBarInit { return }
// 非根控制器重新设置返回按钮
var isRootVC = false
if let nav = self.navigationController, nav.children.first == self {
isRootVC = true
}
if !isRootVC && self.gk_backImage != nil && self.gk_navLeftBarButtonItem == nil && self.gk_navLeftBarButtonItems == nil {
setBackItemImage(image: self.gk_backImage)
}
// 重新设置导航栏背景颜色
if self.gk_navBackgroundImage != nil {
setNavBackground(self.gk_navBackgroundImage)
}else {
setNavBackground(self.gk_navBackgroundColor)
}
// 重新设置分割线颜色
if self.gk_navShadowImage != nil {
setNavShadow(self.gk_navShadowImage)
}else {
setNavShadow(self.gk_navShadowColor)
}
}
}
gk_traitCollectionDidChange(previousTraitCollection)
}
// MARK: - Public Funtions
public func showNavLine() {
self.gk_navLineHidden = false
}
public func hideNavLine() {
self.gk_navLineHidden = true
}
public func refreshNavBarFrame() {
self.setupNavBarFrame()
}
@objc open func backItemClick(_ sender: Any) {
var shouldPop = navigationShouldPop()
let selector = NSSelectorFromString("navigationShouldPopOnClick")
if self.responds(to: selector) {
if self.perform(selector) != nil {
shouldPop = true
}else {
shouldPop = false
}
}
if shouldPop {
self.navigationController?.popViewController(animated: true)
}
}
public func gk_findCurrentViewController(_ isRoot: Bool) -> UIViewController? {
if canFindPresented(self.presentedViewController) {
return self.presentedViewController?.gk_findCurrentViewController(false)
}
if self.isKind(of: UITabBarController.self) {
let tabbarVC = self as! UITabBarController
return tabbarVC.selectedViewController?.gk_findCurrentViewController(false)
}
if self.isKind(of: UINavigationController.self) {
let navVC = self as! UINavigationController
return navVC.topViewController?.gk_findCurrentViewController(false)
}
if self.children.count > 0 {
if self.children.count == 1 && isRoot {
return self.children.first?.gk_findCurrentViewController(false)
}else {
var currentVC: UIViewController? = self
for obj in self.children {
if obj.isViewLoaded {
let point = obj.view.convert(CGPoint.zero, to: nil)
let windowSize = obj.view.window?.bounds.size ?? .zero
// 是否全屏显示
let isFullScreenShow = !obj.view.isHidden && obj.view.alpha > 0.01 && __CGPointEqualToPoint(point, .zero) && __CGSizeEqualToSize(obj.view.bounds.size, windowSize)
// 判断类型
let isStopFindController = obj.isKind(of: UINavigationController.self) || obj.isKind(of: UITabBarController.self)
if isFullScreenShow && isStopFindController {
currentVC = obj.gk_findCurrentViewController(false)
break
}
}
}
return currentVC
}
}else if self.responds(to: NSSelectorFromString("contentViewController")) {
let tempVC = self.perform(NSSelectorFromString("contentViewController")).retain().takeRetainedValue() as? UIViewController
if tempVC != nil {
return tempVC?.gk_findCurrentViewController(false)
}
}
return self
}
fileprivate func canFindPresented(_ viewController: UIViewController?) -> Bool {
guard let vc = viewController else { return false }
if vc.isKind(of: UIAlertController.self) {
return false
}
if NSStringFromClass(self.classForCoder) == "_UIContextMenuActionsOnlyViewController" {
return false
}
return true
}
// MARK: - Private Functions
fileprivate func shouldHandleNavBar() -> Bool {
if self.gk_navBarInit {
return true
}
if self.isKind(of: UITabBarController.self) {
return false
}
if let vc = self.parent, vc.isKind(of: UINavigationController.self) {
return true
}
return false
}
fileprivate func shouldFixItemSpace() -> Bool {
if self.gk_navBarInit {
if self.isKind(of: UINavigationController.self) {
return false
}
if self.isKind(of: UITabBarController.self) {
return false
}
if self.navigationController == nil {
return false
}
if let parent = self.parent, !parent.isKind(of: UINavigationController.self) {
return false
}
return true
}
return self.gk_openFixNavItemSpace
}
fileprivate func hiddenSystemNavBar() {
if let nav = self.navigationController, nav.isNavigationBarHidden == false {
nav.gk_hideNavigationBar = true
nav.isNavigationBarHidden = true
}
}
fileprivate func restoreSystemNavBar() {
if GKConfigure.gk_restoreSystemNavBar && self.shouldHandleNavBar() {
if let nav = self.navigationController, nav.isNavigationBarHidden, nav.gk_hideNavigationBar {
nav.isNavigationBarHidden = false
}
}
}
fileprivate func setupNavBarAppearance() {
// 设置默认背景
if self.gk_navBackgroundImage == nil {
self.gk_navBackgroundImage = GKConfigure.backgroundImage
}
if self.gk_darkNavBackgroundImage == nil {
self.gk_darkNavBackgroundImage = GKConfigure.darkBackgroundImage
}
if self.gk_navBackgroundColor == nil && self.gk_navBackgroundImage == nil {
self.gk_navBackgroundColor = GKConfigure.backgroundColor
}
// 设置分割线
if self.gk_navShadowImage == nil {
self.gk_navShadowImage = GKConfigure.lineImage
}
if self.gk_darkNavShadowImage == nil {
self.gk_darkNavShadowImage = GKConfigure.darkLineImage
}
if self.gk_navShadowColor == nil && self.gk_navShadowImage == nil {
self.gk_navShadowColor = GKConfigure.lineColor
}
// 设置分割线是否隐藏
if self.gk_navLineHidden == false && GKConfigure.lineHidden == true {
self.gk_navLineHidden = GKConfigure.lineHidden
}
// 设置默认标题字体
if self.gk_navTitleFont == nil {
self.gk_navTitleFont = GKConfigure.titleFont
}
// 设置默认标题颜色
if self.gk_navTitleColor == nil {
self.gk_navTitleColor = GKConfigure.titleColor
}
// 设置默认返回按钮图片
if self.gk_backImage == nil {
self.gk_backImage = GKConfigure.backImage
}
if self.gk_darkBackImage == nil {
self.gk_darkBackImage = GKConfigure.darkBackImage
}
// 设置默认返回样式
if self.gk_backStyle == .none {
self.gk_backStyle = GKConfigure.backStyle
}
self.gk_navTitle = nil
}
fileprivate func setupNavBarFrame() {
let isNonFullScreen = isNonFullScreen()
var navBarH: CGFloat = 0.0
let gkNavBarHNFS = GKDevice.navBarHeightNonFullScreen()
let gkNavBarH = GKDevice.navBarHeight()
let gkStatusBarH = GKDevice.statusBarFrame().size.height
let gkStatusBarNavBarH = gkStatusBarH + gkNavBarH
if GKDevice.isIPad { // iPad
if isNonFullScreen {
navBarH = gkNavBarHNFS
self.gk_navigationBar.gk_nonFullScreen = true
}else {
navBarH = self.gk_statusBarHidden ? gkNavBarH : gkStatusBarNavBarH
}
}else if GKDevice.isLandScape() { // 横屏不显示状态栏,没有非全屏模式
navBarH = gkNavBarH
}else {
if isNonFullScreen {
navBarH = gkNavBarHNFS
self.gk_navigationBar.gk_nonFullScreen = true
}else {
if GKDevice.isNotchedScreen { // 刘海屏手机
// iPhone 14 Pro 状态栏高度与安全区域高度不一致,这里改为使用状态栏高度
var topH = GKDevice.STATUSBAR_HEIGHT()
if topH == 0 { topH = GKDevice.safeAreaInsets().top }
navBarH = topH + gkNavBarH
} else {
navBarH = self.gk_statusBarHidden ? gkNavBarH : gkStatusBarNavBarH
}
}
}
self.gk_navigationBar.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: navBarH)
self.gk_navigationBar.gk_statusBarHidden = self.gk_statusBarHidden
self.gk_navigationBar.layoutSubviews()
}
fileprivate func isNonFullScreen() -> Bool {
var isNonFullScreen = false
var viewW = self.view.bounds.width
var viewH = self.view.bounds.height
if self.isViewLoaded {
var parentVC = self
// 找到最上层的父控制器
while (parentVC.parent != nil) {
parentVC = parentVC.parent!
}
viewW = parentVC.view.frame.size.width
viewH = parentVC.view.frame.size.height
if viewW == 0 || viewH == 0 {
return false
}
// 如果是通过present方式弹出且高度小于屏幕高度,则认为是非全屏
var window = view.window
if window == nil {
window = GKDevice.keyWindow()
}
isNonFullScreen = (self.presentingViewController != nil) && viewH < window?.bounds.height ?? 0
}
return isNonFullScreen
}
fileprivate func setBackItemImage(image: UIImage?) {
if self.gk_navBarInit == false { return }
// 根控制器不作处理
guard let count = self.navigationController?.children.count else { return }
if (count <= 1) {
self.gk_navLeftBarButtonItem = nil
return
}
var backImage = image
if #available(iOS 12.0, *) {
if self.traitCollection.userInterfaceStyle == .dark, self.gk_darkBackImage != nil {
backImage = self.gk_darkBackImage
}
}
if backImage == nil {
if self.gk_backStyle != .none {
backImage = self.gk_backStyle == .black ? self.gk_blackBackImage : self.gk_whiteBackImage
}
}else {
if self.gk_backStyle == .none {
backImage = nil
}
}
if backImage == nil { return }
let btn = UIButton()
btn.setImage(backImage, for: .normal)
btn.frame.size.width = 40
btn.contentHorizontalAlignment = .left
btn.addTarget(self, action: #selector(backItemClick(_:)), for: .touchUpInside)
self.gk_navigationItem.leftBarButtonItem = UIBarButtonItem(customView: btn)
// self.gk_navigationItem.leftBarButtonItem = UIBarButtonItem.gk_item(image: backImage, target: self, action: #selector(backItemClick(_:)))
}
fileprivate func setNavBackground(_ image: UIImage?) {
guard var image = image else { return }
if #available(iOS 12.0, *) {
if traitCollection.userInterfaceStyle == .dark, gk_darkNavBackgroundImage != nil {
image = gk_darkNavBackgroundImage!
}
}
setNavBackground(image, color: nil)
}
fileprivate func setNavBackground(_ color: UIColor?) {
guard let color = color else { return }
setNavBackground(nil, color: color)
}
fileprivate func setNavShadow(_ image: UIImage?) {
guard var image = image else { return }
if #available(iOS 12.0, *) {
if traitCollection.userInterfaceStyle == .dark, gk_darkNavShadowImage != nil {
image = gk_darkNavShadowImage!
}
}
setNavShadow(image, color: nil)
}
fileprivate func setNavShadow(_ color: UIColor?) {
guard let color = color else { return }
setNavShadow(nil, color: color)
}
fileprivate func setNavTitle(_ color: UIColor?) {
guard let color = color else { return }
var attr = [NSAttributedString.Key: AnyObject]()
attr[.foregroundColor] = color
if gk_navTitleFont != nil {
attr[.font] = gk_navTitleFont
}
setNavTitle(attr)
}
fileprivate func setNavTitle(_ font: UIFont?) {
guard let font = font else { return }
var attr = [NSAttributedString.Key: Any]()
if gk_navTitleColor != nil {
attr[.foregroundColor] = gk_navTitleColor
}
attr[.font] = font
setNavTitle(attr)
}
fileprivate func setNavBackground(_ image: UIImage?, color: UIColor?) {
if #available(iOS 13.0, *) {
let appearance = gk_navigationBar.standardAppearance
let shadowColor = appearance.shadowColor
let shadowImage = appearance.shadowImage
appearance.configureWithTransparentBackground()
appearance.backgroundImage = image
appearance.backgroundColor = color
appearance.shadowColor = shadowColor
appearance.shadowImage = shadowImage
gk_navigationBar.standardAppearance = appearance
gk_navigationBar.scrollEdgeAppearance = appearance
}else {
var bgImage = image
if bgImage == nil, let color = color {
bgImage = UIImage.gk_image(with: color)
}
gk_navigationBar.setBackgroundImage(bgImage, for: .default)
}
}
fileprivate func setNavShadow(_ image: UIImage?, color: UIColor?) {
if #available(iOS 13.0, *) {
let appearance = gk_navigationBar.standardAppearance
let backgroundColor = appearance.backgroundColor
let backgroundImage = appearance.backgroundImage
appearance.configureWithTransparentBackground()
appearance.shadowImage = image
appearance.shadowColor = color
appearance.backgroundColor = backgroundColor
appearance.backgroundImage = backgroundImage
gk_navigationBar.standardAppearance = appearance
gk_navigationBar.scrollEdgeAppearance = appearance
}else {
var shadowImage = image
if shadowImage == nil, let color = color {
shadowImage = UIImage.gk_change(with: UIImage.gk_image(with: "nav_line"), color: color)
}
gk_navigationBar.shadowImage = shadowImage
}
}
fileprivate func setNavTitle(_ attr: [NSAttributedString.Key: Any]) {
if #available(iOS 13, *) {
let appearance = gk_navigationBar.standardAppearance
appearance.titleTextAttributes = attr
gk_navigationBar.standardAppearance = appearance
gk_navigationBar.scrollEdgeAppearance = appearance
}else {
gk_navigationBar.titleTextAttributes = attr
}
}
}
//
// UIViewController+GKGesture.swift
// GKNavigationBarSwift
//
// Created by QuintGao on 2022/3/18.
// Copyright © 2022 QuintGao. All rights reserved.
//
import UIKit
// 左滑push代理
@objc public protocol GKViewControllerPushDelegate: NSObjectProtocol {
/// 左滑push,在这里创建将要push的控制器
@objc optional func pushToNextViewController()
/// push手势滑动开始
@objc optional func viewControllerPushScrollBegan()
/// push手势滑动进度更新
/// - Parameter progress: 进度(0-1)
@objc optional func viewControllerPushScrollUpdate(progress: CGFloat)
/// push手势滑动结束
/// - Parameter finished: 是否完成push操作(true:push成功 false:push取消)
@objc optional func viewControllerPushScrollEnded(finished: Bool)
}
// 右滑pop代理
@objc public protocol GKViewControllerPopDelegate: NSObjectProtocol {
/// pop手势滑动开始
@objc optional func viewControllerPopScrollBegan()
/// pop手势滑动进度更新
/// - Parameter progress: 进度(0-1)
@objc optional func viewControllerPopScrollUpdate(progress: CGFloat)
/// pop手势滑动结束
/// - Parameter finished: 是否完成pop操作(true:pop成功 false:pop取消)
@objc optional func viewControllerPopScrollEnded(finished: Bool)
}
// 返回拦截
@objc public protocol GKGesturePopHandlerProtocol: NSObjectProtocol {
/// 是否可以返回,包括点击返回和手势返回,默认YES
@objc func navigationShouldPop() -> Bool
/// 是否可以手势返回
@objc optional func navigationShouldPopOnGesture() -> Bool
/// 是否可以点击返回
@objc optional func navigationShouldPopOnClick() -> Bool
/// 返回手势冲突处理,当返回手势与其他手势冲突如:WKWebView中的手势,可实现以下方法返回YES,让返回手势与其他手势共存来解决手势冲突
@objc optional func popGestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
}
public let GKViewControllerPropertyChanged = NSNotification.Name(rawValue: "GKViewControllerPropertyChanged")
extension UIViewController: GKGestureAwakeProtocol {
// MARK: - 重新系统方法
private static let onceToken = UUID().uuidString
@objc public static func gkGestureAwake() {
DispatchQueue.once(token: onceToken) {
let oriSels = ["viewWillAppear:",
"viewDidAppear:",
"viewDidDisappear:"]
for oriSel in oriSels {
gk_swizzled_instanceMethod("gkGesture", oldClass: self, oldSelector: oriSel, newClass: self)
}
}
}
@objc func gkGesture_viewWillAppear(_ animated: Bool) {
if self.hasPushDelegate {
self.gk_pushDelegate = self as? GKViewControllerPushDelegate
self.hasPushDelegate = false
}
if self.hasPopDelegate {
self.gk_popDelegate = self as? GKViewControllerPopDelegate
self.hasPopDelegate = false
}
gkGesture_viewWillAppear(animated)
}
@objc func gkGesture_viewDidAppear(_ animated: Bool) {
postPropertyChangeNotification()
gkGesture_viewDidAppear(animated)
}
@objc func gkGesture_viewDidDisappear(_ animated: Bool) {
if let delegate = self.gk_pushDelegate as? NSObject, delegate == self {
self.hasPushDelegate = true
}
if let delegate = self.gk_popDelegate as? NSObject, delegate == self {
self.hasPopDelegate = true
}
// 这两个代理系统不会自动回收,所以要做下处理
self.gk_pushDelegate = nil;
self.gk_popDelegate = nil;
gkGesture_viewDidDisappear(animated)
}
fileprivate func postPropertyChangeNotification() {
NotificationCenter.default.post(name: GKViewControllerPropertyChanged, object: ["viewController": self])
}
}
extension UIViewController {
fileprivate struct AssociatedKeys {
static var gkInteractivePopDisabled: Void?
static var gkFullScreenPopDisabled: Void?
static var gkSystemGestureHandleDisabled: Void?
static var gkMaxPopDistance: Void?
static var gkPushDelegate: Void?
static var gkPopDelegate: Void?
static var gkPushTransition: Void?
static var gkPopTransition: Void?
static var hasPushDelegate: Void?
static var hasPopDelegate: Void?
}
public var gk_interactivePopDisabled: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkInteractivePopDisabled) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkInteractivePopDisabled, newValue)
postPropertyChangeNotification()
}
}
public var gk_fullScreenPopDisabled: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkFullScreenPopDisabled) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkFullScreenPopDisabled, newValue)
postPropertyChangeNotification()
}
}
public var gk_systemGestureHandleDisabled: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkSystemGestureHandleDisabled) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkSystemGestureHandleDisabled, newValue)
postPropertyChangeNotification()
}
}
public var gk_maxPopDistance: CGFloat {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.gkMaxPopDistance) as? CGFloat else { return 0 }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkMaxPopDistance, newValue)
postPropertyChangeNotification()
}
}
public var gk_pushDelegate: GKViewControllerPushDelegate? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkPushDelegate) as? GKViewControllerPushDelegate
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkPushDelegate, newValue)
}
}
public var gk_popDelegate: GKViewControllerPopDelegate? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkPopDelegate) as? GKViewControllerPopDelegate
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkPopDelegate, newValue)
}
}
public var gk_pushTransition: UIViewControllerAnimatedTransitioning? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkPushTransition) as? UIViewControllerAnimatedTransitioning
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkPushTransition, newValue)
}
}
public var gk_popTransition: UIViewControllerAnimatedTransitioning? {
get {
return gk_getAssociatedObject(self, &AssociatedKeys.gkPopTransition) as? UIViewControllerAnimatedTransitioning
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.gkPopTransition, newValue)
}
}
fileprivate var hasPushDelegate: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.hasPushDelegate) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.hasPushDelegate, newValue)
}
}
fileprivate var hasPopDelegate: Bool {
get {
guard let obj = gk_getAssociatedObject(self, &AssociatedKeys.hasPopDelegate) as? Bool else { return false }
return obj
}
set {
gk_setAssociatedObject(self, &AssociatedKeys.hasPopDelegate, newValue)
}
}
}
extension UIViewController: GKGesturePopHandlerProtocol {
open func navigationShouldPop() -> Bool {
return true
}
}
platform :ios, '14.0'
target 'NumberCube' do
use_frameworks!
pod 'R.swift', '~> 7.8.0'
pod 'CocoaLumberjack/Swift'
pod 'Then', '~> 3.0.0'
pod 'SnapKit', '~> 5.7.1'
pod 'PinLayout', '~> 1.10.5'
pod 'Toast-Swift', '~> 5.1.1'
pod 'SwiftHEXColors'
end
install! 'cocoapods', :warn_for_unused_master_specs_repo => false
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'].to_f < 14.0
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.0'
end
end
end
end
PODS:
- CocoaLumberjack/Core (3.8.5)
- CocoaLumberjack/Swift (3.8.5):
- CocoaLumberjack/Core
- PinLayout (1.10.5)
- R.swift (7.8.0)
- SnapKit (5.7.1)
- SwiftHEXColors (1.4.1)
- Then (3.0.0)
- Toast-Swift (5.1.1)
DEPENDENCIES:
- CocoaLumberjack/Swift
- PinLayout (~> 1.10.5)
- R.swift (~> 7.8.0)
- SnapKit (~> 5.7.1)
- SwiftHEXColors
- Then (~> 3.0.0)
- Toast-Swift (~> 5.1.1)
SPEC REPOS:
trunk:
- CocoaLumberjack
- PinLayout
- R.swift
- SnapKit
- SwiftHEXColors
- Then
- Toast-Swift
SPEC CHECKSUMS:
CocoaLumberjack: 6a459bc897d6d80bd1b8c78482ec7ad05dffc3f0
PinLayout: f6c2b63a5a5b24864064e1d15c67de41b4e74748
R.swift: f573269ca45b2ab066c082e363dd4c2b297b0d71
SnapKit: d612e99e678a2d3b95bf60b0705ed0a35c03484a
SwiftHEXColors: 1cb6e5d55c52749aa33db8f088ac55eb71ca4c7f
Then: 844265ae87834bbe1147d91d5d41a404da2ec27d
Toast-Swift: 7a03a532afe3a560d4044bc7c237e2864d295173
PODFILE CHECKSUM: 85592ef7bd84e20246dcb0d05cd1e278defb118d
COCOAPODS: 1.16.2
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!