繁体   English   中英

iOS:为多个视图重用UIPanGestureRecognizer类/方法的正确方法?

[英]IOS : Correct way to reuse UIPanGestureRecognizer class / methods for multiple view?

我需要对所有视图重用手势方法,因为我不想在所有视图中重复该方法。

因此,我想创建一个通用的UIPanGestureRecognizer类来注册视图并调用委托方法到相应的视图。

实际上,我已经尝试过但遇到了一些问题。 因此,请给我任何建议或参考。

好的,这是我的代码,

@objc protocol PanGestureRecognizerDelegate: UIGestureRecognizerDelegate{

    /// Called when the pan gesture recognizer starts.
    @objc optional func panGestureRecognizer(didStart gestureRecognizer: PanGestureRecognizer)

    /// Called when the pan gesture recognizer updates.
    @objc optional func panGestureRecognizer(didUpdate gestureRecognizer: PanGestureRecognizer)

    /// Called when the pan gesture recognizer cancels. A pan gesture recognizer may cancel if its translation or velocity in `initialDirection` is less than the value of `minimumTranslation` or `minimumVelocity`, respectively.
    @objc optional func panGestureRecognizer(didCancel gestureRecognizer: PanGestureRecognizer)

    /// Called when the pan gesture recognizer finishes. A pan gesture recognizer may finish if its translation and velocity in `initialDirection` are greater than or equal to the value of `minimumTranslation` or `minimumVelocity`, respectively.
    @objc optional func panGestureRecognizer(didFinish gestureRecognizer: PanGestureRecognizer)

}

class PanGestureRecognizer: UIPanGestureRecognizer {

    public enum Direction {
        /// The pan gesture recognizer's touches move upwards.
        case up
        /// The pan gesture recognizer's touches move leftwards.
        case left
        /// The pan gesture recognizer's touches move downwards.
        case down
        /// The pan gesture recognizer's touches move rightwards.
        case right
    }

    @IBInspectable open var minimumTranslation: CGFloat = 0.0

    /// Minimum velocity (in `initialDirection`) required for the gesture to finish. Defaults to `0.0`.
    @IBInspectable open var minimumVelocity: CGFloat = 0.0

    // MARK: Internal variables

    /// The current location in `view` when the pan gesture recognizer begins. Defaults to `nil`. Resets to `nil` when `reset()` is called.
    open fileprivate(set) var initialLocation: CGPoint?

    /// The current direction in `view` when the pan gesture recognizer begins. Defaults to `nil`. Resets to `nil` when `reset()` is called.
    open fileprivate(set) var initialDirection: Direction?

    // MARK: Delegation

    open override var delegate: UIGestureRecognizerDelegate? {
        didSet {
            self.addTarget(self, action: #selector(handlePan))
        }
    }

    internal var panDelegate: PanGestureRecognizerDelegate? {
        return delegate as? PanGestureRecognizerDelegate
    }

    // MARK: Initialization

    /// Initialize the pan gesture recognizer with no target or action set.
    public convenience init() {
        self.init(target: nil, action: nil)
    }

    // MARK: Overrides

    open override func reset() {
        super.reset()

        initialLocation = nil
        initialDirection = nil
    }

    // MARK: Actions

    internal func handlePan() {

        if (state == .began) {
            initialLocation = location
            initialDirection = direction
        }

        switch state {
        case .began:

            panDelegate?.panGestureRecognizer?(didStart: self)
        case .changed:
            panDelegate?.panGestureRecognizer?(didUpdate: self)
        case .cancelled:
            panDelegate?.panGestureRecognizer?(didCancel: self)
        case .ended where shouldCancel():
            panDelegate?.panGestureRecognizer?(didCancel: self)
        case .ended:
            panDelegate?.panGestureRecognizer?(didFinish: self)
        default:
            break
        }

        // set recognizer translation to zero
        self.setTranslation(CGPoint.zero, in: view)
    }

    // MARK: Cancellation

    fileprivate func shouldCancel() -> Bool {
        return translation() < minimumTranslation || velocity() < minimumVelocity
    }
}

// MARK: - Dynamic variables

extension PanGestureRecognizer {

    /// The pan gesture recognizer's current location in `view`, calculated using `location(in:)`. Returns `nil` if `view` is `nil`.
    public var location: CGPoint? {
        guard let view = view else {
            return nil
        }

        return location(in:view)
    }

    /// The pan gesture recognizer's current direction in `view`, calculated using `translation(in:)`. Returns `nil` if `view` is `nil`.
    public var direction: Direction? {
        guard let view = view else {
            return nil
        }

        let translation = self.translation(in: view)

        if (translation == .zero) {
            return nil
        } else if (fabs(translation.x) < fabs(translation.y)) {
            return translation.y > 0.0 ? .down : .up
        } else {
            return translation.x > 0.0 ? .right : .left
        }
    }

}

// MARK: - Directional helpers

extension PanGestureRecognizer {

    public func translation(inDirection direction: Direction? = nil) -> CGFloat {
        guard let direction = direction ?? initialDirection, let view = view else {
            return 0.0
        }

        return translation(in: view).magnitude(inDirection: direction)
    }

    public func velocity(in direction: Direction? = nil) -> CGFloat {
        guard let direction = direction ?? initialDirection, let view = view else {
            return 0.0
        }

        return velocity(in: view).magnitude(inDirection: direction)
    }

    public func translationPoint() -> CGPoint {
        return translation(in: view)
    }

    public func velocityPoint() -> CGPoint {
        return velocity(in: view)
    }
}

而且,我已经在情节提要中添加了手势,并将其细分为子类。

@IBOutlet weak var panGestureRecognizer: PanGestureRecognizer!

如下更新我的视图,

// MARK: View state

public func updateView() {

    let translation = self.panGestureRecognizer.translationPoint()
    //let velocity  = self.panGestureRecognizer.velocity(in: direction)

    let originY = self.view.frame.origin.y + translation.y

    let MIN :CGFloat = 0
    let MAX :CGFloat = (self.view.height - kMaxTranslation)

    if(originY <= MIN || originY >= MAX){
        return
    }

    self.view.frame.origin.y = originY
}

我正在按如下方式调用委托方法,

// MARK: - UIGestureRecognizerDelegate

extension MyViewController : UIGestureRecognizerDelegate {

    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        guard let g = self.panGestureRecognizer else { return false }
        guard g.view is UIScrollView else { return false }
        return true
    }

    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy
        otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return false
    }
}

// MARK: - Pan gesture recognizer delegate

extension MyViewController: PanGestureRecognizerDelegate {

    @objc(panGestureRecognizerWithDidStart:) func panGestureRecognizer(didStart gestureRecognizer: PanGestureRecognizer) {
        updateView()
    }

    @objc(panGestureRecognizerWithDidUpdate:) func panGestureRecognizer(didUpdate gestureRecognizer: PanGestureRecognizer) {
        updateView()
    }

    @objc(panGestureRecognizerWithDidCancel:) func panGestureRecognizer(didCancel gestureRecognizer: PanGestureRecognizer) {
        updateView()
    }

    @objc(panGestureRecognizerWithDidFinish:) func panGestureRecognizer(didFinish gestureRecognizer: PanGestureRecognizer) {
        updateView()
    }
}

我添加了一个带有手势的通用视图控制器,并将其扩展到我所有的视图控制器。

现在,它工作正常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM