Swift中通过运行时实现全屏的pop功能
2017-08-01 本文已影响81人
sayHellooX
最近碰见个小的功能需求,就是需要给push的视图控制器添加一个侧滑pop弹出的功能,找了点资料,发现一个比较不错的解决办法,用了相识已久,但是没用过的运行时功能来实现。
具体思路如下:
- 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))
}
}