Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swift 版本增加黑名单功能 #33

Open
shen0607 opened this issue Nov 12, 2018 · 0 comments
Open

Swift 版本增加黑名单功能 #33

shen0607 opened this issue Nov 12, 2018 · 0 comments

Comments

@shen0607
Copy link

`//
// WRNavigationBar.swift
// WRNavigationBar_swift
//
// Created by wangrui on 2017/4/19.
// Copyright © 2017年 wangrui. All rights reserved.
//
// Github地址:https://github.com/wangrui460/WRNavigationBar_swift
import UIKit

extension UINavigationBar:WRAwakeProtocol
{
fileprivate struct AssociatedKeys {
static var backgroundView: UIView = UIView()
static var backgroundImageView: UIImageView = UIImageView()
}

fileprivate var backgroundView:UIView? {
    get {
        guard let bgView = objc_getAssociatedObject(self, &AssociatedKeys.backgroundView) as? UIView else {
            return nil
        }
        return bgView
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.backgroundView, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

fileprivate var backgroundImageView:UIImageView? {
    get {
        guard let bgImageView = objc_getAssociatedObject(self, &AssociatedKeys.backgroundImageView) as? UIImageView else {
            return nil
        }
        return bgImageView
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.backgroundImageView, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

// set navigationBar backgroundImage
fileprivate func wr_setBackgroundImage(image:UIImage)
{
    backgroundView?.removeFromSuperview()
    backgroundView = nil
    if (backgroundImageView == nil)
    {
        // add a image(nil color) to _UIBarBackground make it clear
        setBackgroundImage(UIImage(), for: .default)
        backgroundImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: Int(bounds.width), height: WRNavigationBar.navBarBottom()))
        backgroundImageView?.autoresizingMask = .flexibleWidth
        // _UIBarBackground is first subView for navigationBar
        subviews.first?.insertSubview(backgroundImageView ?? UIImageView(), at: 0)
    }
    backgroundImageView?.image = image
}

// set navigationBar barTintColor
fileprivate func wr_setBackgroundColor(color:UIColor)
{
    // 注释掉,不然导航栏会闪一下
    backgroundImageView?.removeFromSuperview()
    backgroundImageView = nil
    if (backgroundView == nil)
    {
        // add a image(nil color) to _UIBarBackground make it clear
        setBackgroundImage(UIImage(), for: .default)
        backgroundView = UIView(frame: CGRect(x: 0, y: 0, width: Int(bounds.width), height: WRNavigationBar.navBarBottom()))
        backgroundView?.autoresizingMask =  .flexibleWidth
        // _UIBarBackground is first subView for navigationBar
        subviews.first?.insertSubview(backgroundView ?? UIView(), at: 0)
    }
    backgroundView?.backgroundColor = color
}

// set _UIBarBackground alpha (_UIBarBackground subviews alpha <= _UIBarBackground alpha)
fileprivate func wr_setBackgroundAlpha(alpha:CGFloat)
{
    if let barBackgroundView = subviews.first
    {
        if #available(iOS 11.0, *)
        {   // sometimes we can't change _UIBarBackground alpha
            for view in barBackgroundView.subviews {
                view.alpha = alpha
            }
        } else {
            barBackgroundView.alpha = alpha
        }
    }
}

// 设置导航栏所有BarButtonItem的透明度
func wr_setBarButtonItemsAlpha(alpha:CGFloat, hasSystemBackIndicator:Bool)
{
    for view in subviews
    {
        if (hasSystemBackIndicator == true)
        {
            // _UIBarBackground/_UINavigationBarBackground对应的view是系统导航栏,不需要改变其透明度
            if let _UIBarBackgroundClass = NSClassFromString("_UIBarBackground")
            {
                if view.isKind(of: _UIBarBackgroundClass) == false {
                    view.alpha = alpha
                }
            }
            
            if let _UINavigationBarBackground = NSClassFromString("_UINavigationBarBackground")
            {
                if view.isKind(of: _UINavigationBarBackground) == false {
                    view.alpha = alpha
                }
            }
        }
        else
        {
            // 这里如果不做判断的话,会显示 backIndicatorImage(系统返回按钮)
            if let _UINavigationBarBackIndicatorViewClass = NSClassFromString("_UINavigationBarBackIndicatorView"),
                view.isKind(of: _UINavigationBarBackIndicatorViewClass) == false
            {
                if let _UIBarBackgroundClass = NSClassFromString("_UIBarBackground")
                {
                    if view.isKind(of: _UIBarBackgroundClass) == false {
                        view.alpha = alpha
                    }
                }
                
                if let _UINavigationBarBackground = NSClassFromString("_UINavigationBarBackground")
                {
                    if view.isKind(of: _UINavigationBarBackground) == false {
                        view.alpha = alpha
                    }
                }
            }
        }
    }
}

/// 设置导航栏在垂直方向上平移多少距离
func wr_setTranslationY(translationY:CGFloat)
{
    transform = CGAffineTransform.init(translationX: 0, y: translationY)
}

func wr_getTranslationY() -> CGFloat
{
    return transform.ty
}

// call swizzling methods active 主动调用交换方法
private static let onceToken = UUID().uuidString
public static func wrAwake()
{
    DispatchQueue.once(token: onceToken)
    {
        let needSwizzleSelectorArr = [
            #selector(setter: titleTextAttributes)
        ]
        
        for selector in needSwizzleSelectorArr {
            let str = ("wr_" + selector.description)
            if let originalMethod = class_getInstanceMethod(self, selector),
                let swizzledMethod = class_getInstanceMethod(self, Selector(str)) {
                method_exchangeImplementations(originalMethod, swizzledMethod)
            }
        }
    }
}

//==========================================================================
// MARK: swizzling pop
//==========================================================================
@objc func wr_setTitleTextAttributes(_ newTitleTextAttributes:[String : Any]?)
{
    guard var attributes = newTitleTextAttributes else {
        return
    }
    
    guard let originTitleTextAttributes = titleTextAttributes else {
        wr_setTitleTextAttributes(attributes)
        return
    }
    
    var titleColor:UIColor?
    for attribute in originTitleTextAttributes {
        if attribute.key == NSAttributedStringKey.foregroundColor {
            titleColor = attribute.value as? UIColor
            break
        }
    }
    
    guard let originTitleColor = titleColor else {
        wr_setTitleTextAttributes(attributes)
        return
    }
    
    if attributes[NSAttributedStringKey.foregroundColor.rawValue] == nil {
        attributes.updateValue(originTitleColor, forKey: NSAttributedStringKey.foregroundColor.rawValue)
    }
    wr_setTitleTextAttributes(attributes)
}

}

//==========================================================================
// MARK: - UINavigationController
//==========================================================================
extension UINavigationController: WRFatherAwakeProtocol
{
override open var preferredStatusBarStyle: UIStatusBarStyle {
return topViewController?.wrStatusBarStyle ?? WRNavigationBar.defaultStatusBarStyle
}

fileprivate func setNeedsNavigationBarUpdate(backgroundImage: UIImage)
{
    navigationBar.wr_setBackgroundImage(image: backgroundImage)
}

fileprivate func setNeedsNavigationBarUpdate(barTintColor: UIColor)
{
    navigationBar.wr_setBackgroundColor(color: barTintColor)
}

fileprivate func setNeedsNavigationBarUpdate(barBackgroundAlpha: CGFloat)
{
    navigationBar.wr_setBackgroundAlpha(alpha: barBackgroundAlpha)
}

fileprivate func setNeedsNavigationBarUpdate(tintColor: UIColor) {
    navigationBar.tintColor = tintColor
}

fileprivate func setNeedsNavigationBarUpdate(hideShadowImage: Bool)
{
    navigationBar.shadowImage = (hideShadowImage == true) ? UIImage() : nil
}

fileprivate func setNeedsNavigationBarUpdate(titleColor: UIColor)
{
    guard let titleTextAttributes = navigationBar.titleTextAttributes else {
        navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor:titleColor]
        return
    }
    
    var newTitleTextAttributes = titleTextAttributes
    newTitleTextAttributes.updateValue(titleColor, forKey: NSAttributedStringKey.foregroundColor)
    navigationBar.titleTextAttributes = newTitleTextAttributes
}

fileprivate func updateNavigationBar(fromVC: UIViewController?, toVC: UIViewController?, progress: CGFloat)
{
    // change navBarBarTintColor
    let fromBarTintColor = fromVC?.navBarBarTintColor ?? WRNavigationBar.defaultNavBarBarTintColor
    let toBarTintColor   = toVC?.navBarBarTintColor ?? WRNavigationBar.defaultNavBarBarTintColor
    let newBarTintColor  = WRNavigationBar.middleColor(fromColor: fromBarTintColor, toColor: toBarTintColor, percent: progress)

// setNeedsNavigationBarUpdate(barTintColor: newBarTintColor)
// modify by sxiangyu
if WRNavigationBar.needUpdateNavigationBar(vc: fromVC) || WRNavigationBar.needUpdateNavigationBar(vc: toVC) {
setNeedsNavigationBarUpdate(barTintColor: newBarTintColor)
}

    // change navBarTintColor
    let fromTintColor = fromVC?.navBarTintColor ?? WRNavigationBar.defaultNavBarTintColor
    let toTintColor = toVC?.navBarTintColor ?? WRNavigationBar.defaultNavBarTintColor
    let newTintColor = WRNavigationBar.middleColor(fromColor: fromTintColor, toColor: toTintColor, percent: progress)

// setNeedsNavigationBarUpdate(tintColor: newTintColor)
// modify by sxiangyu
if WRNavigationBar.needUpdateNavigationBar(vc: fromVC) {
setNeedsNavigationBarUpdate(tintColor: newTintColor)
}

    // change navBarTitleColor
    //        let fromTitleColor = fromVC?.navBarTitleColor ?? WRNavigationBar.defaultNavBarTitleColor
    //        let toTitleColor = toVC?.navBarTitleColor ?? WRNavigationBar.defaultNavBarTitleColor
    //        let newTitleColor = WRNavigationBar.middleColor(fromColor: fromTitleColor, toColor: toTitleColor, percent: progress)
    //        setNeedsNavigationBarUpdate(titleColor: newTitleColor)
    
    // change navBar _UIBarBackground alpha
    let fromBarBackgroundAlpha = fromVC?.navBarBackgroundAlpha ?? WRNavigationBar.defaultBackgroundAlpha
    let toBarBackgroundAlpha = toVC?.navBarBackgroundAlpha ?? WRNavigationBar.defaultBackgroundAlpha
    let newBarBackgroundAlpha = WRNavigationBar.middleAlpha(fromAlpha: fromBarBackgroundAlpha, toAlpha: toBarBackgroundAlpha, percent: progress)
    setNeedsNavigationBarUpdate(barBackgroundAlpha: newBarBackgroundAlpha)
}

// call swizzling methods active 主动调用交换方法
private static let onceToken = UUID().uuidString
public static func fatherAwake()
{
    DispatchQueue.once(token: onceToken)
    {
        let needSwizzleSelectorArr = [
            NSSelectorFromString("_updateInteractiveTransition:"),
            #selector(popToViewController),
            #selector(popToRootViewController),
            #selector(pushViewController)
        ]
        
        for selector in needSwizzleSelectorArr {
            // _updateInteractiveTransition:  =>  wr_updateInteractiveTransition:
            let str = ("wr_" + selector.description).replacingOccurrences(of: "__", with: "_")
            if let originalMethod = class_getInstanceMethod(self, selector),
                let swizzledMethod = class_getInstanceMethod(self, Selector(str)) {
                method_exchangeImplementations(originalMethod, swizzledMethod)
            }
        }
    }
}

//==========================================================================
// MARK: swizzling pop
//==========================================================================
struct popProperties {
    fileprivate static let popDuration = 0.13
    fileprivate static var displayCount = 0
    fileprivate static var popProgress:CGFloat {
        let all:CGFloat = CGFloat(60.0 * popDuration)
        let current = min(all, CGFloat(displayCount))
        return current / all
    }
}

// swizzling system method: popToViewController
@objc func wr_popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]?
{
    setNeedsNavigationBarUpdate(titleColor: viewController.navBarTitleColor)
    var displayLink:CADisplayLink? = CADisplayLink(target: self, selector: #selector(popNeedDisplay))
    // UITrackingRunLoopMode: 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
    // NSRunLoopCommonModes contains kCFRunLoopDefaultMode and UITrackingRunLoopMode
    displayLink?.add(to: RunLoop.main, forMode: .commonModes)
    CATransaction.setCompletionBlock {
        displayLink?.invalidate()
        displayLink = nil
        popProperties.displayCount = 0
    }
    CATransaction.setAnimationDuration(popProperties.popDuration)
    CATransaction.begin()
    let vcs = wr_popToViewController(viewController, animated: animated)
    CATransaction.commit()
    return vcs
}

// swizzling system method: popToRootViewControllerAnimated
@objc func wr_popToRootViewControllerAnimated(_ animated: Bool) -> [UIViewController]?
{
    var displayLink:CADisplayLink? = CADisplayLink(target: self, selector: #selector(popNeedDisplay))
    displayLink?.add(to: RunLoop.main, forMode: .commonModes)
    CATransaction.setCompletionBlock {
        displayLink?.invalidate()
        displayLink = nil
        popProperties.displayCount = 0
    }
    CATransaction.setAnimationDuration(popProperties.popDuration)
    CATransaction.begin()
    let vcs = wr_popToRootViewControllerAnimated(animated)
    CATransaction.commit()
    return vcs;
}

// change navigationBar barTintColor smooth before pop to current VC finished
@objc fileprivate func popNeedDisplay()
{
    guard let topViewController = topViewController,
        let coordinator       = topViewController.transitionCoordinator else {
            return
    }
    
    popProperties.displayCount += 1
    let popProgress = popProperties.popProgress
    // print("第\(popProperties.displayCount)次pop的进度:\(popProgress)")
    let fromVC = coordinator.viewController(forKey: .from)
    let toVC = coordinator.viewController(forKey: .to)
    updateNavigationBar(fromVC: fromVC, toVC: toVC, progress: popProgress)
}


//==========================================================================
// MARK: swizzling push
//==========================================================================
struct pushProperties {
    fileprivate static let pushDuration = 0.13
    fileprivate static var displayCount = 0
    fileprivate static var pushProgress:CGFloat {
        let all:CGFloat = CGFloat(60.0 * pushDuration)
        let current = min(all, CGFloat(displayCount))
        return current / all
    }
}

// swizzling system method: pushViewController
@objc func wr_pushViewController(_ viewController: UIViewController, animated: Bool)
{
    var displayLink:CADisplayLink? = CADisplayLink(target: self, selector: #selector(pushNeedDisplay))
    displayLink?.add(to: RunLoop.main, forMode: .commonModes)
    CATransaction.setCompletionBlock {
        displayLink?.invalidate()
        displayLink = nil
        pushProperties.displayCount = 0
        viewController.pushToCurrentVCFinished = true
    };
    CATransaction.setAnimationDuration(pushProperties.pushDuration)
    CATransaction.begin()
    wr_pushViewController(viewController, animated: animated)
    CATransaction.commit()
}

// change navigationBar barTintColor smooth before push to current VC finished or before pop to current VC finished
@objc fileprivate func pushNeedDisplay()
{
    guard let topViewController = topViewController,
        let coordinator       = topViewController.transitionCoordinator else {
            return
    }
    
    pushProperties.displayCount += 1
    let pushProgress = pushProperties.pushProgress
    // print("第\(pushProperties.displayCount)次push的进度:\(pushProgress)")
    let fromVC = coordinator.viewController(forKey: .from)
    let toVC = coordinator.viewController(forKey: .to)
    updateNavigationBar(fromVC: fromVC, toVC: toVC, progress: pushProgress)
}

}

//==========================================================================
// MARK: - deal the gesture of return
//==========================================================================
extension UINavigationController: UINavigationBarDelegate
{
public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool
{
if let topVC = topViewController,
let coor = topVC.transitionCoordinator, coor.initiallyInteractive {
if #available(iOS 10.0, *) {
coor.notifyWhenInteractionChanges({ (context) in
self.dealInteractionChanges(context)
})
} else {
coor.notifyWhenInteractionEnds({ (context) in
self.dealInteractionChanges(context)
})
}
return true
}

    let itemCount = navigationBar.items?.count ?? 0
    let n = viewControllers.count >= itemCount ? 2 : 1
    let popToVC = viewControllers[viewControllers.count - n]
    
    popToViewController(popToVC, animated: true)
    return true
}

// deal the gesture of return break off
private func dealInteractionChanges(_ context: UIViewControllerTransitionCoordinatorContext)
{
    let animations: (UITransitionContextViewControllerKey) -> () = {
        let curColor = context.viewController(forKey: $0)?.navBarBarTintColor ?? WRNavigationBar.defaultNavBarBarTintColor
        let curAlpha = context.viewController(forKey: $0)?.navBarBackgroundAlpha ?? WRNavigationBar.defaultBackgroundAlpha
        
        self.setNeedsNavigationBarUpdate(barTintColor: curColor)
        self.setNeedsNavigationBarUpdate(barBackgroundAlpha: curAlpha)
    }
    
    // after that, cancel the gesture of return
    if context.isCancelled
    {
        let cancelDuration: TimeInterval = context.transitionDuration * Double(context.percentComplete)
        UIView.animate(withDuration: cancelDuration) {
            animations(.from)
        }
    }
    else
    {
        // after that, finish the gesture of return
        let finishDuration: TimeInterval = context.transitionDuration * Double(1 - context.percentComplete)
        UIView.animate(withDuration: finishDuration) {
            animations(.to)
        }
    }
}

// swizzling system method: _updateInteractiveTransition
@objc func wr_updateInteractiveTransition(_ percentComplete: CGFloat)
{
    guard let topViewController = topViewController,
        let coordinator       = topViewController.transitionCoordinator else {
            wr_updateInteractiveTransition(percentComplete)
            return
    }
    
    let fromVC = coordinator.viewController(forKey: .from)
    let toVC = coordinator.viewController(forKey: .to)
    updateNavigationBar(fromVC: fromVC, toVC: toVC, progress: percentComplete)
    
    wr_updateInteractiveTransition(percentComplete)
}

}

//=============================================================================
// MARK: - store navigationBar barTintColor and tintColor every viewController
//=============================================================================
extension UIViewController: WRAwakeProtocol
{
fileprivate struct AssociatedKeys
{
static var pushToCurrentVCFinished: Bool = false
static var pushToNextVCFinished:Bool = false

    static var navBarBackgroundImage: UIImage = UIImage()
    
    static var navBarBarTintColor: UIColor = WRNavigationBar.defaultNavBarBarTintColor
    static var navBarBackgroundAlpha:CGFloat = 1.0
    static var navBarTintColor: UIColor = WRNavigationBar.defaultNavBarTintColor
    static var navBarTitleColor: UIColor = WRNavigationBar.defaultNavBarTitleColor
    static var wrStatusBarStyle: UIStatusBarStyle = UIStatusBarStyle.default
    static var navBarShadowImageHidden: Bool = false
    
    static var customNavBar: UINavigationBar = UINavigationBar()
}

// navigationBar barTintColor can not change by currentVC before fromVC push to currentVC finished
fileprivate var pushToCurrentVCFinished:Bool {
    get {
        guard let isFinished = objc_getAssociatedObject(self, &AssociatedKeys.pushToCurrentVCFinished) as? Bool else {
            return false
        }
        return isFinished
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.pushToCurrentVCFinished, newValue, .OBJC_ASSOCIATION_ASSIGN)
    }
}

// navigationBar barTintColor can not change by currentVC when currentVC push to nextVC finished
fileprivate var pushToNextVCFinished:Bool {
    get {
        guard let isFinished = objc_getAssociatedObject(self, &AssociatedKeys.pushToNextVCFinished) as? Bool else {
            return false
        }
        return isFinished
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.pushToNextVCFinished, newValue, .OBJC_ASSOCIATION_ASSIGN)
    }
}

// you can set navigationBar backgroundImage
var navBarBackgroundImage: UIImage?
{
    get {
        guard let bgImage = objc_getAssociatedObject(self, &AssociatedKeys.navBarBackgroundImage) as? UIImage else {
            return WRNavigationBar.defaultNavBarBackgroundImage
        }
        return bgImage
    }
    //        set {
    //            if customNavBar.isKind(of: UINavigationBar.self) {
    //                let navBar = customNavBar as! UINavigationBar
    //                navBar.wr_setBackgroundImage(image: newValue!)
    //            }
    //            else {
    //                objc_setAssociatedObject(self, &AssociatedKeys.navBarBackgroundImage, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    //            }
    //        }
}

// navigationBar barTintColor
var navBarBarTintColor: UIColor {
    get {
        
        /// add by sxiangyu
        guard WRNavigationBar.needUpdateNavigationBar(vc: self) else {
            return self.navigationController?.navigationBar.barTintColor ?? WRNavigationBar.defaultNavBarBarTintColor
        }
        
        guard let barTintColor = objc_getAssociatedObject(self, &AssociatedKeys.navBarBarTintColor) as? UIColor else {
            return WRNavigationBar.defaultNavBarBarTintColor
        }
        return barTintColor
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.navBarBarTintColor, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        
        if customNavBar.isKind(of: UINavigationBar.self) {
            //                let navBar = customNavBar as! UINavigationBar
            //                navBar.wr_setBackgroundColor(color: newValue)
        }
        else {
            if canUpdateNavBarBarTintColorOrBackgroundAlpha == true {
                navigationController?.setNeedsNavigationBarUpdate(barTintColor: newValue)
            }
        }
    }
}

// navigationBar _UIBarBackground alpha
var navBarBackgroundAlpha:CGFloat {
    get {
        guard let barBackgroundAlpha = objc_getAssociatedObject(self, &AssociatedKeys.navBarBackgroundAlpha) as? CGFloat else {
            return 1.0
        }
        return barBackgroundAlpha
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.navBarBackgroundAlpha, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        
        if customNavBar.isKind(of: UINavigationBar.self) {
            //                let navBar = customNavBar as! UINavigationBar
            //                navBar.wr_setBackgroundAlpha(alpha: newValue)
        }
        else {
            if canUpdateNavBarBarTintColorOrBackgroundAlpha == true {
                navigationController?.setNeedsNavigationBarUpdate(barBackgroundAlpha: newValue)
            }
        }
    }
}
private var canUpdateNavBarBarTintColorOrBackgroundAlpha:Bool {
    get {
        let isRootViewController = self.navigationController?.viewControllers.first == self
        if (pushToCurrentVCFinished == true || isRootViewController == true) && pushToNextVCFinished == false {
            return true
        } else {
            return false
        }
    }
}

// navigationBar tintColor
var navBarTintColor: UIColor {
    get {
        
        /// add by sxiangyu
        guard WRNavigationBar.needUpdateNavigationBar(vc: self) else {
            return self.navigationController?.navigationBar.tintColor ?? WRNavigationBar.defaultNavBarTintColor
        }
        
        guard let tintColor = objc_getAssociatedObject(self, &AssociatedKeys.navBarTintColor) as? UIColor else {
            return WRNavigationBar.defaultNavBarTintColor
        }
        return tintColor
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.navBarTintColor, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        
        if customNavBar.isKind(of: UINavigationBar.self) {
            //                let navBar = customNavBar as! UINavigationBar
            //                navBar.tintColor = newValue
        }
        else
        {
            if pushToNextVCFinished == false {
                navigationController?.setNeedsNavigationBarUpdate(tintColor: newValue)
            }
        }
    }
}

// navigationBar titleColor
var navBarTitleColor: UIColor {
    get {
        
        /// add by sxiangyu
        guard WRNavigationBar.needUpdateNavigationBar(vc: self) else {
            return (self.navigationController?.navigationBar.titleTextAttributes?[NSAttributedStringKey.foregroundColor] as? UIColor) ?? WRNavigationBar.defaultNavBarTitleColor
        }
        
        guard let titleColor = objc_getAssociatedObject(self, &AssociatedKeys.navBarTitleColor) as? UIColor else {
            return WRNavigationBar.defaultNavBarTitleColor
        }
        return titleColor
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.navBarTitleColor, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        
        if customNavBar.isKind(of: UINavigationBar.self) {
            //                let navBar = customNavBar as! UINavigationBar
            //                navBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor:newValue]
        }
        else
        {
            if pushToNextVCFinished == false {
                navigationController?.setNeedsNavigationBarUpdate(titleColor: newValue)
            }
        }
    }
}

// statusBarStyle
var wrStatusBarStyle: UIStatusBarStyle {
    get {
        guard let style = objc_getAssociatedObject(self, &AssociatedKeys.wrStatusBarStyle) as? UIStatusBarStyle else {
            return WRNavigationBar.defaultStatusBarStyle
        }
        return style
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.wrStatusBarStyle, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        setNeedsStatusBarAppearanceUpdate()
    }
}

// if you want shadowImage hidden,you can via hideShadowImage = true
var navBarShadowImageHidden:Bool {
    get {
        guard let isHidden = objc_getAssociatedObject(self, &AssociatedKeys.navBarShadowImageHidden) as? Bool else {
            return WRNavigationBar.defaultShadowImageHidden
        }
        return isHidden
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.navBarShadowImageHidden, newValue, .OBJC_ASSOCIATION_ASSIGN)
        navigationController?.setNeedsNavigationBarUpdate(hideShadowImage: newValue)
    }
}

// custom navigationBar
var customNavBar: UIView {
    get {
        guard let navBar = objc_getAssociatedObject(self, &AssociatedKeys.customNavBar) as? UINavigationBar else {
            return UIView()
        }
        return navBar
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.customNavBar, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

// swizzling two system methods: viewWillAppear(_:) and viewWillDisappear(_:)
private static let onceToken = UUID().uuidString
@objc public static func wrAwake()
{
    DispatchQueue.once(token: onceToken)
    {
        let needSwizzleSelectors = [
            #selector(viewWillAppear(_:)),
            #selector(viewWillDisappear(_:)),
            #selector(viewDidAppear(_:))
        ]
        
        for selector in needSwizzleSelectors
        {
            let newSelectorStr = "wr_" + selector.description
            if let originalMethod = class_getInstanceMethod(self, selector),
                let swizzledMethod = class_getInstanceMethod(self, Selector(newSelectorStr)) {
                method_exchangeImplementations(originalMethod, swizzledMethod)
            }
        }
    }
}

@objc func wr_viewWillAppear(_ animated: Bool)
{
    if canUpdateNavigationBar() == true {
        pushToNextVCFinished = false
        navigationController?.setNeedsNavigationBarUpdate(tintColor: navBarTintColor)
        navigationController?.setNeedsNavigationBarUpdate(titleColor: navBarTitleColor)
    }
    wr_viewWillAppear(animated)
}

@objc func wr_viewWillDisappear(_ animated: Bool)
{
    if canUpdateNavigationBar() == true {
        pushToNextVCFinished = true
    }
    wr_viewWillDisappear(animated)
}

@objc func wr_viewDidAppear(_ animated: Bool)
{
    
    if self.navigationController?.viewControllers.first != self {
        self.pushToCurrentVCFinished = true
    }
    if canUpdateNavigationBar() == true
    {
        if let navBarBgImage = navBarBackgroundImage {
            navigationController?.setNeedsNavigationBarUpdate(backgroundImage: navBarBgImage)
        } else {
            navigationController?.setNeedsNavigationBarUpdate(barTintColor: navBarBarTintColor)
        }
        navigationController?.setNeedsNavigationBarUpdate(barBackgroundAlpha: navBarBackgroundAlpha)
        navigationController?.setNeedsNavigationBarUpdate(tintColor: navBarTintColor)
        navigationController?.setNeedsNavigationBarUpdate(titleColor: navBarTitleColor)
        navigationController?.setNeedsNavigationBarUpdate(hideShadowImage: navBarShadowImageHidden)
    }
    wr_viewDidAppear(animated)
}

func canUpdateNavigationBar() -> Bool
{
    /// add by sxiangyu
    guard WRNavigationBar.needUpdateNavigationBar(vc: self) else {
        return false
    }
    
    let viewFrame = view.frame
    let maxFrame = UIScreen.main.bounds
    let middleFrame = CGRect(x: 0, y: WRNavigationBar.navBarBottom(), width: WRNavigationBar.screenWidth(), height: WRNavigationBar.screenHeight()-WRNavigationBar.navBarBottom())
    let minFrame = CGRect(x: 0, y: WRNavigationBar.navBarBottom(), width: WRNavigationBar.screenWidth(), height: WRNavigationBar.screenHeight()-WRNavigationBar.navBarBottom()-WRNavigationBar.tabBarHeight())
    // 蝙蝠🦇
    let isBat = viewFrame.equalTo(maxFrame) || viewFrame.equalTo(middleFrame) || viewFrame.equalTo(minFrame)
    if self.navigationController != nil && isBat == true {
        return true
    } else {
        return false
    }
}

}

//====================================================================================
// 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()
}

}

//===========================================================================================
// MARK: - default navigationBar barTintColor、tintColor and statusBarStyle YOU CAN CHANGE!!!
//===========================================================================================
class WRNavigationBar
{
fileprivate struct AssociatedKeys
{ // default is system attributes
static var defNavBarBarTintColor: UIColor = UIColor.white
static var defNavBarBackgroundImage: UIImage = UIImage()
static var defNavBarTintColor: UIColor = UIColor(red: 0, green: 0.478431, blue: 1, alpha: 1.0)
static var defNavBarTitleColor: UIColor = UIColor.black
static var defStatusBarStyle: UIStatusBarStyle = UIStatusBarStyle.default
static var defShadowImageHidden: Bool = false
}

class var defaultNavBarBarTintColor: UIColor {
    get {
        guard let def = objc_getAssociatedObject(self, &AssociatedKeys.defNavBarBarTintColor) as? UIColor else {
            return AssociatedKeys.defNavBarBarTintColor
        }
        return def
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.defNavBarBarTintColor, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

class var defaultNavBarBackgroundImage: UIImage? {
    get {
        guard let def = objc_getAssociatedObject(self, &AssociatedKeys.defNavBarBackgroundImage) as? UIImage else {
            return nil
        }
        return def
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.defNavBarBackgroundImage, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

class var defaultNavBarTintColor: UIColor {
    get {
        guard let def = objc_getAssociatedObject(self, &AssociatedKeys.defNavBarTintColor) as? UIColor else {
            return AssociatedKeys.defNavBarTintColor
        }
        return def
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.defNavBarTintColor, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

class var defaultNavBarTitleColor: UIColor {
    get {
        guard let def = objc_getAssociatedObject(self, &AssociatedKeys.defNavBarTitleColor) as? UIColor else {
            return AssociatedKeys.defNavBarTitleColor
        }
        return def
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.defNavBarTitleColor, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

class var defaultStatusBarStyle: UIStatusBarStyle {
    get {
        guard let def = objc_getAssociatedObject(self, &AssociatedKeys.defStatusBarStyle) as? UIStatusBarStyle else {
            return .default
        }
        return def
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.defStatusBarStyle, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

class var defaultShadowImageHidden: Bool {
    get {
        guard let def = objc_getAssociatedObject(self, &AssociatedKeys.defShadowImageHidden) as? Bool else {
            return false
        }
        return def
    }
    set {
        objc_setAssociatedObject(self, &AssociatedKeys.defShadowImageHidden, newValue, .OBJC_ASSOCIATION_ASSIGN)
    }
}

class var defaultBackgroundAlpha: CGFloat {
    get {
        return 1.0
    }
}

// Calculate the middle Color with translation percent
class fileprivate func middleColor(fromColor: UIColor, toColor: UIColor, percent: CGFloat) -> UIColor
{
    // get current color RGBA
    var fromRed: CGFloat = 0
    var fromGreen: CGFloat = 0
    var fromBlue: CGFloat = 0
    var fromAlpha: CGFloat = 0
    fromColor.getRed(&fromRed, green: &fromGreen, blue: &fromBlue, alpha: &fromAlpha)
    
    // get to color RGBA
    var toRed: CGFloat = 0
    var toGreen: CGFloat = 0
    var toBlue: CGFloat = 0
    var toAlpha: CGFloat = 0
    toColor.getRed(&toRed, green: &toGreen, blue: &toBlue, alpha: &toAlpha)
    
    // calculate middle color RGBA
    let newRed = fromRed + (toRed - fromRed) * percent
    let newGreen = fromGreen + (toGreen - fromGreen) * percent
    let newBlue = fromBlue + (toBlue - fromBlue) * percent
    let newAlpha = fromAlpha + (toAlpha - fromAlpha) * percent
    return UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: newAlpha)
}

// Calculate the middle alpha
class fileprivate func middleAlpha(fromAlpha: CGFloat, toAlpha: CGFloat, percent: CGFloat) -> CGFloat
{
    let newAlpha = fromAlpha + (toAlpha - fromAlpha) * percent
    return newAlpha
}

/// add by sxiangyu 是否需要更新
class fileprivate func needUpdateNavigationBar(vc: UIViewController?) -> Bool {
    
    if let _ = vc as? INNOBaseViewController {
        return true
    } else {
        return false
    }
    
}

}

extension WRNavigationBar
{
class func isIphoneX() -> Bool {
return UIScreen.main.bounds.equalTo(CGRect(x: 0, y: 0, width: 375, height: 812)) ||
UIScreen.main.bounds.equalTo(CGRect(x: 0, y: 0, width: 812, height: 375)) ||
UIScreen.main.bounds.equalTo(CGRect(x: 0, y: 0, width: 414, height: 896)) ||
UIScreen.main.bounds.equalTo(CGRect(x: 0, y: 0, width: 896, height: 414))
}
class func navBarBottom() -> Int {
return self.isIphoneX() ? 88 : 64;
}
class func tabBarHeight() -> Int {
return self.isIphoneX() ? 83 : 49;
}
class func screenWidth() -> Int {
return Int(UIScreen.main.bounds.size.width)
}
class func screenHeight() -> Int {
return Int(UIScreen.main.bounds.size.height)
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 1. 定义 WRAwakeProtocol 协议
public protocol WRAwakeProtocol: class {
static func wrAwake()
}
public protocol WRFatherAwakeProtocol: class
{ // 1.1 定义 WRFatherAwakeProtocol ()
static func fatherAwake()
}

class NothingToSeeHere
{
static func harmlessFunction(){
// let typeCount = Int(objc_getClassList(nil, 0))
// let types = UnsafeMutablePointer<AnyClass?>.allocate(capacity: typeCount)
// let autoreleaseintTypes = AutoreleasingUnsafeMutablePointer(types)
// objc_getClassList(autoreleaseintTypes, Int32(typeCount)) //获取所有的类
// for index in 0 ..< typeCount {
// (types[index] as? WRAwakeProtocol.Type)?.wrAwake() //如果该类实现了SelfAware协议,那么调用 awake 方法
// (types[index] as? WRFatherAwakeProtocol.Type)?.fatherAwake()
// }
// types.deallocate(capacity: typeCount)

    // !!!这边不能按照注释的写循环,否则启动会卡住线程(15000多个循环)
    
    // 实现了SelfAware协议,那么调用 awake 方法
    UINavigationBar.wrAwake()
    UIViewController.wrAwake()
    UINavigationController.fatherAwake()
}

}

// 2. 让APP启动时只执行一次 harmlessFunction 方法
extension UIApplication
{
private static let runOnce:Void = { //使用静态属性以保证只调用一次(该属性是个方法)
NothingToSeeHere.harmlessFunction()
}()

open override var next: UIResponder?{ //重写next属性
    UIApplication.runOnce
    return super.next
}

}

// 3. 自定义类实现 WRAwakeProtocol 协议,重写 wrAwake 方法
// 自定义类实现 WRFatherAwakeProtocol 协议,重写 fatherAwake 方法
`

主要修改
`class fileprivate func needUpdateNavigationBar(vc: UIViewController?) -> Bool {

    if let _ = vc as? INNOBaseViewController {
        return true
    } else {
        return false
    }
    
}`

这里面的方法,我这边是有个公共的baseVC ,所以这样判断,大家可以可以设置黑名单列表之类的,在这里面判断。主要模仿OC的方式。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant