美文网首页
Swift中通过运行时实现全屏的pop功能

Swift中通过运行时实现全屏的pop功能

作者: sayHellooX | 来源:发表于2017-08-01 15:10 被阅读81次

    最近碰见个小的功能需求,就是需要给push的视图控制器添加一个侧滑pop弹出的功能,找了点资料,发现一个比较不错的解决办法,用了相识已久,但是没用过的运行时功能来实现。

    具体思路如下:

      1. push到 UINavigationController 中的控制器视图,系统默认是给添加了一个边缘侧滑pop回上一页的方法的,这个功能是 UINavigationController 通过属性 var interactivePopGestureRecognizer: UIGestureRecognizer? 实现的
    • 2.因为 UIGestureRecognizer 都是通过target 和action来实现具体的操作的,所以我们可以将系统的这个边缘策划pop的手势,通过运行时把他的target 和action取出来添加到我们自建的手势上,完活。

    代码如下:

    //通过 class_copyIvarList() 方法获得UIGestureRecognizer的所有变量 包括 property及{ }中的
    override func viewDidLoad() {
            super.viewDidLoad()
            var count: UInt32 = 0
            let ivars = class_copyIvarList(UIGestureRecognizer.self, &count)!
            for i in 0..<count {
                //获得变量的名字
                let nameP = ivar_getName(ivars[Int(i)])!
                let name = String.init(cString: nameP)
                print(name)
            }
    }
    //输出如下
    /*
    _gestureFlags
    _targets
    _delayedTouches
    _delayedPresses
    _view
    _lastTouchTimestamp
    _state
    _allowedTouchTypes
    _initialTouchType
    _internalActiveTouches
    _forceClassifier
    _requiredPreviewForceState
    _touchForceObservable
    _touchForceObservableAndClassifierObservation
    _forceTargets
    _forcePressCount
    _beganObservable
    _failureRequirements
    _failureDependents
    _delegate
    _allowedPressTypes
    _gestureEnvironment
    */
    

    我们目测(当然要靠一点猜测了😜)_targets 这个变量 应该是负责 action 和target相关的属性,所以我们通过KVC来具体查看一下

     let tempTargets = interactivePopGestureRecognizer?.value(forKey: "_targets")
     print(tempTargets)
    //输出如下
    /*
    Optional(<__NSArrayM 0x60000004be80>(
    (action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7f88db500670>)
    )
    )
    */
    

    从输出中我们可以看出来确实有我们需要的action 和 target
    我们可以通过KVC将对应的值取出来

            guard let targets = interactivePopGestureRecognizer?.value(forKey: "_targets") as? [NSObject] else {
                return
            }
            let targetObjct = targets.first
            let target = targetObjct?.value(forKey: "target")
            let action = targetObjct?.value(forKey: "action")
    

    这样取出来会造成崩溃,提示没有action这个值(为啥还真不知道...),所以将action的获取更改如下:

    //直接通过字符进行封装
    let action = Selector(("handleNavigationTransition:"))
    

    这样我们的目的就达到了,有了 target 和 action ,我们将target 和 action添加到对应的手势上就可以了
    因为我们要求的是某一些固定push的页面都拥有这个功能,所以我们通过自定义UINavigationController,然后将这个手势添加在了UINavigationController的view上,这样所有的栈内的控制器都有这个全局pop的功能了,全部代码如下:

    //UINavigationController 中
    class CustomNavController: UINavigationController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            //通过运行时获得手势中的隐藏属性
            //var interactivePopGestureRecognizer: UIGestureRecognizer? UINavigationController自带的边缘pop手势
            var count: UInt32 = 0
            let ivars = class_copyIvarList(UIGestureRecognizer.self, &count)!
            for i in 0..<count {
                let nameP = ivar_getName(ivars[Int(i)])!
                let name = String.init(cString: nameP)
                //print(name)
            }
            
            let tempTargets = interactivePopGestureRecognizer?.value(forKey: "_targets")
           // print(tempTargets)
            
            guard let targets = interactivePopGestureRecognizer?.value(forKey: "_targets") as? [NSObject] else {
                return
            }
            let targetObjct = targets.first
            let target = targetObjct?.value(forKey: "target")
            let action = Selector(("handleNavigationTransition:"))
            view.addGestureRecognizer(UIPanGestureRecognizer(target: target, action: action))
        }
    }
    
    

    相关文章

      网友评论

          本文标题:Swift中通过运行时实现全屏的pop功能

          本文链接:https://www.haomeiwen.com/subject/ruejlxtx.html