Home > Enterprise >  Extension UIViewController - Costume transition , problem with @objc func parametr
Extension UIViewController - Costume transition , problem with @objc func parametr

Time:12-24

I want to create an extension for UIViewController but I have one problem with my @objc func. How to pass this parameter below?

#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)
    }
}

what am I doing wrong ? When I am calling func "panGestureRecognizerToHandleDragAndDissmisView" I want to pass this parameter "cardOriginY"

CodePudding user response:

UIPanGestureRecognizer's selector can take only one argument and it's UIPanGestureRecognizer itself. Basically it should look like this

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

In your concrete situation, you need to pass one more argument for your calculations cardOriginY. I can propose you to do the next thing:

  1. Add DismissableCardContainer for reusing ability
  2. Add PanGestureActionHandler to avoid unnecessary complications with @objc modifiers
  3. Implement DismissableCardContainer protocol for your purpose

Here's the code:

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)
  }
}

After that there's only left to conform DismissableCardContainer protocol where you need it

  • Related