Commit e8292061 ilCode

init project

1 个父辈 fc6d3474
正在显示 76 个修改的文件 包含 1852 行增加145 行删除
......@@ -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)
}
}
}
//
// 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?) {
}
}
//
// 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)
}
}
}
//
// 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+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!