1. 程式人生 > >在 UIView 上新增返回上一級操作介面(手勢)

在 UIView 上新增返回上一級操作介面(手勢)

系統:手勢 ——> 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:"))