【问题标题】:UIPanGestureRecognizer doesn't trigger actionUIPanGestureRecognizer 不触发动作
【发布时间】:2018-09-05 21:09:49
【问题描述】:

我正在尝试创建 UIView 的子类,以便通过平移来扩展视图。它应该以这种方式工作:如果用户朝顶部平移,则视图的高度会降低,相反,如果平移朝底部,则它应该增加。为了实现该功能,我正在尝试将 UIPanGestureRecognizer 添加到视图中,但它似乎不起作用。我是这样做的:

第一个sn-p是uiView子类声明

class ExpandibleView: UIView {
    //Here I create the reference to the recognizer
    let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))

    //And here I set its minimumNumberOfTouches and maximumNumberOfTouches properties and add it to the view
    func initialize() {
        panGestureRecognizer.minimumNumberOfTouches = 1
        panGestureRecognizer.maximumNumberOfTouches = 1
        self.addGestureRecognizer(panGestureRecognizer)
    }

    //here's the function that should handle the pan but who instead doesn't seem to been called at all
    @objc func handlePan(_ sender:UIPanGestureRecognizer) {
        //Here's I handle the Pan
    }
}

第二个是视图控制器内部的实现。

class MapViewController: UIViewController {
    @IBOutlet weak var profileView: ExpandibleView!

    //MARK: - ViewController Delegate Methods

    override func viewDidLoad() {
        super.viewDidLoad()

        //Here I set the View
        profileView.isUserInteractionEnabled = true
        profileView.initialize()
        profileView.minHeight = 100
        profileView.maxHeight = 190
    }

}

我在情节提要中将视图的类设置为我创建的子类,但识别器根本不会触发处理程序。

【问题讨论】:

    标签: ios swift uiview uipangesturerecognizer


    【解决方案1】:

    您遇到的问题是由于您在此处的类定义中定义了panGestureRecognizer 变量:

    //Here I create the reference to the recognizer
    let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
    

    您可以通过这种方式对其进行初始化,但在创建此变量时似乎没有设置self。因此,您的操作永远不会被注册。

    有几种方法可以使用您的代码解决此问题,您可以继续将其初始化为实例变量,但您需要在 initialize() 函数中设置目标/操作

    let panGestureRecognizer = UIPanGestureRecognizer()
    
    func initialize() {
        // add your target/action here
        panGestureRecognizer.addTarget(self, action: #selector(handlePan(_:)))
        panGestureRecognizer.minimumNumberOfTouches = 1
        panGestureRecognizer.maximumNumberOfTouches = 1
        addGestureRecognizer(panGestureRecognizer)
    }
    

    或者您可以在初始化函数中简单地初始化手势识别器,而不使用实例变量

    func initialize() {
        let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
        panGestureRecognizer.minimumNumberOfTouches = 1
        panGestureRecognizer.maximumNumberOfTouches = 1
        addGestureRecognizer(panGestureRecognizer)
    }
    

    我原来的答案

    这是一个解决方案,它使用带有故事板中定义的视图的约束或直接操作框架。

    约束示例

    import UIKit
    
    // Delegate protocol for managing constraint updates if needed
    protocol MorphDelegate: class {
    
        // tells the delegate to change its size constraints
        func morph(x: CGFloat, y: CGFloat)
    }
    
    class ExpandableView: UIView {
    
        var delegate: MorphDelegate?
    
        init() {
            // frame is set later if needed by creator when using this init method
            super.init(frame: CGRect.zero)
            configureGestureRecognizers()
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            configureGestureRecognizers()
        }
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            configureGestureRecognizers()
        }
    
        // setup UIPanGestureRecognizer
        internal func configureGestureRecognizers() {
            let panGR = UIPanGestureRecognizer.init(target: self, action: #selector(didPan(_:)))
            addGestureRecognizer(panGR)
        }
    
        @objc func didPan(_ panGR: UIPanGestureRecognizer) {
    
            // get the translation
            let translation = panGR.translation(in: self).applying(transform)
    
            if let delegate = delegate {
    
                // tell delegate to change the constraints using this translation
                delegate.morph(x: translation.x, y: translation.y)
    
            } else {
    
                // If you want the view to expand/contract in opposite direction
                // of drag then swap the + and - in the 2 lines below
                let newOriginY = frame.origin.y + translation.y
                let newHeight = frame.size.height - translation.y
    
                // expand self via frame manipulation
                let newFrame = CGRect(x: frame.origin.x, y: newOriginY, width: frame.size.width, height: newHeight)
                frame = newFrame
            }
    
            // reset translation
            panGR.setTranslation(CGPoint.zero, in: self)
        }
    
    }
    

    如果你想通过在情节提要中定义它并操纵它的约束来使用这个类,你可以这样做。

    首先在情节提要中定义您的视图并限制其宽度和高度。对于演示,我将它的 x 位置限制在视图中心,底部到 SafeArea.bottom

    为视图创建一个 IBOutlet,以及它对 ViewController 文件的高度约束。

    我将本示例的背景颜色设置为蓝色。

    在视图控制器中,我定义了一个函数来设置视图(目前只设置了约束操作回调的委托),然后定义了一个扩展来处理更新约束的委托调用。

    class ViewController: UIViewController {
    
        @IBOutlet weak var expandingView: ExpandableView!
        @IBOutlet weak var constraint_expViewHeight: NSLayoutConstraint!
    
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // call to configure our expanding view
            configureExpandingView()
        }
    
        // this sets the delegate for an expanding view defined in the storyboard
        func configureExpandingView() {
            expandingView.delegate = self
        }
    }
    
    // setup the delegate callback to handle constraint manipulation
    extension ViewController: MorphDelegate {
    
        func morph(x: CGFloat, y: CGFloat) {
    
            // this will update the view's height based on the amount
            // you drag your finger in the view. You can '+=' below if
            // you want to reverse the expanding behavior based on pan
            // movements.
            constraint_expViewHeight.constant -= y
        }
    }
    

    当我运行项目时,通过约束以这种方式进行操作:

    帧操作示例

    要使用它并仅使用框架属性来操作高度,视图控制器可能会像这样实现视图创建:

    override func viewDidLoad() {
        super.viewDidLoad()
    
        setupExpandingView()
    }
    
    func setupExpandingView() {
    
        let newView = ExpandableView()
        newView.backgroundColor = .red
        newView.frame = CGRect(x: 20, y: 200, width: 100, height: 100)
        view.addSubview(newView)
    }
    

    仅使用帧操作我得到了这个:

    【讨论】:

    • 这行得通..非常感谢...另一件事..为了扩展视图,我正在更改高度约束的高度,但是当我这样做时,视图不会扩展。跨度>
    • 我不确定您所说的“我正在更改高度限制高度”是什么意思...您是否正在更改高度限制.constant 属性?此外,如果您使用演示的委托设置,您是否设置扩展视图的委托属性以确保在视图控制器中调用回调?
    【解决方案2】:

    试试改一下

    class ExpandibleView: UIView {
    
        func initialize() {
    
    
        }
    
        //here's the function that should handle the pan but who instead doesn't seem to been called at all
         func handlePan() {
            //your function
        }
    }
    
    class MapViewController: UIViewController {
        @IBOutlet weak var profileView: ExpandibleView!
    
        //MARK: - ViewController Delegate Methods
    
        override func viewDidLoad() {
            super.viewDidLoad()
         let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
         panGestureRecognizer.minimumNumberOfTouches = 1
            panGestureRecognizer.maximumNumberOfTouches = 1
         profileView.addGestureRecognizer(panGestureRecognizer)
            //Here I set the View
            profileView.isUserInteractionEnabled = true
            profileView.initialize()
            profileView.minHeight = 100
            profileView.maxHeight = 190
        }
    
       @objc func handlePan(_ sender:UIPanGestureRecognizer) {
           profileView.handlePan()
        }
    }
    

    或者您可以创建一个委托以在其他视图中调用。

    祝你好运!

    【讨论】:

    • 更改参数类型不起作用。 “在其他视图中为调用创建委托”是什么意思?
    • 它一直不工作..我真的不明白出了什么问题
    猜你喜欢
    • 1970-01-01
    • 2013-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多