在 UIView 上新增返回上一級操作介面(手勢)
阿新 • • 發佈:2018-11-07
系統:手勢 ——> target ----> action
自己建立的介面新增手勢 :UIView —> 建立手勢 —> target —> action
第一種方法
-
獲取到系統的返回上一級介面的手勢,新增到 UIView 上
-
系統的返回上一級介面的手勢
- 屬於導航控制器(NavigationController),而不是 控制器UIViewController
- 系統有一個手勢屬性告訴開發者當前的手勢是什麼
interactivePopGestureRecognizer
第二種方法
- 取出系統手勢中的 target 和 action
- 在自己建立的 View 上面建立一個手勢,在這個手勢上新增 從系統手勢中取出來的 target 和 action
let panGes = UIPanGestureRecognizer(target: nil, action: nil)
view.addGestureRecognizer(panGes)
講解一些 執行時方法
執行時的一些方法
步驟:
- 使用執行時方法獲取到手勢的屬性
- class_copyIvarList(cls: AnyClass?, outCount: UnsafeMutablePointer?)
- cls: AnyClass? : 傳 UIGestureRecognizer.self
- outCount: UnsafeMutablePointer? : 需要傳入一個指標,會告訴你有多少個屬性
- var count: UInt32 = 0
- 寫好後如下:
class_copyIvarList(UIGestureRecognizer.self, &count)
- 這樣就可以拿到所有的 UIPanGestureRecognizer 屬性
完整程式碼:
var count: UInt32 = 0
let ivars = class_copyIvarList(UIGestureRecognizer.self, &count)!
for i in 0..<count {
// 拿出來的是一個指標
let nameP = ivar_getName(ivars[Int(i)])!
// 把上面的指標轉換成 string 型別
let name = String(cString: nameP)
print(name)
}
列印結果
_gestureFlags
_targets
_delayedTouches
_delayedPresses
_view
_lastTouchTimestamp
_firstEventTimestamp
_state
_allowedTouchTypes
_initialTouchType
_internalActiveTouches
_forceClassifier
_requiredPreviewForceState
_touchForceObservable
_touchForceObservableAndClassifierObservation
_forceTargets
_forcePressCount
_beganObservable
_failureRequirements
_failureDependents
_activeEvents
_keepTouchesOnContinuation
_delegate
_allowedPressTypes
_name
_gestureEnvironment
我們用裡面的 _targets
屬性做下一個操作
` let targets = interactivePopGestureRecognizer?.value(forKey: "_targets")`
- 使用 KVC 來操作
- 可以知道 interactivePopGestureRecognizer 對應的 _targets 屬性到底是什麼值 --> 獲取 系統手勢
- 列印結果
targets = Optional(<__NSArrayM 0x60400025fa40>(
(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fe2ea612d60>)
)
)
- 最外層是一個數組,因為 有多個目標 (是 targets,不是 target)
- 所以我們可以把 targets 進行一個轉換 ,轉換成 NSObject 陣列
as? [NSObject]
- 數組裡面存放的是物件型別 [NSObject]
let targets = interactivePopGestureRecognizer?.value(forKey: "_targets") as? [NSObject]
對 targets 進行判斷,如果沒有值,返回 。有值,接著往下走
guard let targets = interactivePopGestureRecognizer?.value(forKey: "_targets") as? [NSObject] else { return }
- 從陣列中把物件取出來
let targetObjc = targets[0]
列印結果
targetObjc = (action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fb4205125a0>)
整體程式碼如下:(錯誤程式碼)
var count: UInt32 = 0
let ivars = class_copyIvarList(UIGestureRecognizer.self, &count)!
for i in 0..<count {
// 拿出來的是一個指標
let nameP = ivar_getName(ivars[Int(i)])!
// 把上面的指標轉換成 string 型別
let name = String(cString: nameP)
}
guard let targets = interactivePopGestureRecognizer?.value(forKey: "_targets") as? [NSObject] else {
return
}
// 從陣列中把物件取出來
let targetObjc = targets[0]
// print("targetObjc = \(targetObjc)")
let target = targetObjc.value(forKey: "target")
let action = targetObjc.value(forKey: "action") as? Selector
let panGes = UIPanGestureRecognizer(target: target, action: action)
view.addGestureRecognizer(panGes)
- 上面程式碼會崩潰:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<UIGestureRecognizerTarget 0x600000232f80> valueForUndefinedKey:]: this class is not key value coding-compliant for the key action.'
因為列印的 action 裡面其實是方法名字,所以可以直接用 Selector 包裝方法名字。
上面的方法只需要修改
let action = Selector(("handleNavigationTransition:"))