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