[英]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.