扩展 UIViewController - 自定义转换,@objc func 参数问题

Extension UIViewController - custom transition , problem with @objc func parametr

我想为 UIViewController 创建一个扩展,但我的 @objc 函数有一个问题。

下面这个参数怎么传?

#selector(handlePanGestExt(sender: **cardOriginY:** )))

    fileprivate var cardOriginY : CGFloat!
    extension UIViewController {
    
    func panGestureRecognizerToHandleDragAndDissmisView(inCardView : UIView, cardOriginY : CGFloat) {
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGestExt(sender: cardOriginY: )))
        inCardView.addGestureRecognizer(panGesture)
    }
    
    @objc func handlePanGestExt(sender: UIPanGestureRecognizer, cardOriginY : CGFloat) {
        let fileView = sender.view!
        
        switch sender.state {
        case .began, .changed:
            moveViewWithPan(view: fileView, sender: sender)
        case .ended:
            let dragVelocity = sender.velocity(in: view)
            if dragVelocity.y >= 1300 {
                dismiss(animated: false, completion: nil)
            } else {
                returnViewToOrigin(view: fileView, cardOriginY: cardOriginY)
            }
        default:
            break
        }
    }
    func moveViewWithPan(view: UIView, sender: UIPanGestureRecognizer) {
        let translation = sender.translation(in: view)
        guard translation.y >= 0 else { return }
        view.center = CGPoint(x:view.center.x, y: view.center.y + translation.y)
        sender.setTranslation(CGPoint.zero, in: view)
    }
    func returnViewToOrigin(view: UIView, cardOriginY : CGFloat) {
        UIView.animate(withDuration: 0.3) {
            view.frame.origin = CGPoint(x: 0.0 , y: cardOriginY)
        }
    }

我做错了什么?当我调用 func panGestureRecognizerToHandleDragAndDissmisView 时,我想传递这个参数 cardOriginY

UIPanGestureRecognizer 的选择器只能接受一个参数,它就是 UIPanGestureRecognizer 本身。基本上它应该是这样的

@objc func handlePanGestExt(_ sender: UIPanGestureRecognizer) {
   // your code here
}

根据您的具体情况,您需要为您的计算再传递一个参数cardOriginY。我可以建议你做下一件事:

  1. 添加DismissableCardContainer重用能力
  2. 添加 PanGestureActionHandler 以避免与 @objc 修饰符出现不必要的并发症
  3. 根据您的目的实施 DismissableCardContainer 协议

代码如下:

protocol DismissableCardContainer: AnyObject {
      func addPanGestureRecognizerToHandleDragAndDissmis(
        to cardView : UIView,
        cardOriginY : CGFloat
      )
  }

extension DismissableCardContainer where Self: UIViewController {
  
  func addPanGestureRecognizerToHandleDragAndDissmis(
    to cardView : UIView,
    cardOriginY : CGFloat
  ) {
    let panGesture = PanGestureActionHandler(
      action: { [weak self] gesture in
        self?.handlePanGestExt(
          gesture,
          cardOriginY
        )
      }
    )
    
    cardView.addGestureRecognizer(panGesture)
  }
  
  private func handlePanGestExt(
    _ sender: UIPanGestureRecognizer,
    _ cardOriginY: CGFloat
  ) {
    let fileView = sender.view!
    
    switch sender.state {
    case .began, .changed:
      moveViewWithPan(view: fileView, sender: sender)
    case .ended:
      let dragVelocity = sender.velocity(in: view)
      if dragVelocity.y >= 1300 {
        dismiss(animated: false, completion: nil)
      } else {
        returnViewToOrigin(view: fileView, cardOriginY: cardOriginY)
      }
    default:
      break
    }
  }
  
  private func moveViewWithPan(view: UIView, sender: UIPanGestureRecognizer) {
    let translation = sender.translation(in: view)
    guard translation.y >= 0 else { return }
    view.center = CGPoint(x:view.center.x, y: view.center.y + translation.y)
    sender.setTranslation(CGPoint.zero, in: view)
  }
  
  private func returnViewToOrigin(view: UIView, cardOriginY : CGFloat) {
    UIView.animate(withDuration: 0.3) {
      view.frame.origin = CGPoint(x: 0.0 , y: cardOriginY)
    }
  }
}

final class PanGestureActionHandler: UIPanGestureRecognizer {
  
  typealias Callback = ((PanGestureActionHandler) -> Void)
  
  private let action: PanGestureActionHandler.Callback
  
  init(
    action: @escaping PanGestureActionHandler.Callback
  ) {
    self.action = action
    
    super.init(target: nil, action: nil)
    
    addTarget(
      self,
      action: #selector(self.handleGestureAction)
    )
  }
  
  @objc private func handleGestureAction(_ gr: UIPanGestureRecognizer) {
    action(gr as! PanGestureActionHandler)
  }
}

在那之后,只剩下在你需要的地方遵守 DismissableCardContainer 协议

final class YourViewController: UIViewController, DismissableCardContainer {
// Your code here
}