UIGestureRecognizer 不向其他类发送操作

Posted

技术标签:

【中文标题】UIGestureRecognizer 不向其他类发送操作【英文标题】:UIGestureRecognizer not sending action to other class 【发布时间】:2018-06-09 18:05:15 【问题描述】:

我正在尝试从 UIView 类上的 UIGestureRecognizer 向其父视图控制器发送操作。

HomeViewController 包含一个包含几个 (5) OperationViews 的视图。

OperationView 扩展了 UIView,看起来像这样:

class OperationView: UIView 
    override func awakeFromNib() 
        super.awakeFromNib()

        // OperationView is on a view that has HomeViewController as it's controller in StoryBoard
        let swipeGestureRecognizer = UISwipeGestureRecognizer(target: HomeViewController.self(), action: #selector(HomeViewController.operatorWasSwiped(_:)))
        swipeGestureRecognizer.direction = .left

        let tapGestureRecognizer = UITapGestureRecognizer(target: HomeViewController.self(), action: #selector(HomeViewController.operatorWasSwiped(_:)))

        self.addGestureRecognizer(swipeGestureRecognizer)
        self.addGestureRecognizer(tapGestureRecognizer)
    

在 HomeViewController 我有这个应该由 UIGestureRecognizers 调用的函数:

@objc func operatorWasSwiped(_ sender : UIGestureRecognizer) 
    if (sender.isKind(of: UITapGestureRecognizer.self))  print("Tapped") 
    else  print("Swiped") 

    self.performSegue(withIdentifier: "segue1", sender: nil)

但是,我什么也没得到。甚至没有错误。

我尝试使用 HomeViewController 上的 IBOutlet 将 UIGestureRecognizer 添加到每个 OperationView:

view1.swipeGestureRecognizer?.addTarget(self, action: #selector(operatorWasSwiped(_ :)))
view2.swipeGestureRecognizer?.addTarget(self, action: #selector(operatorWasSwiped(_ :)))
view3.swipeGestureRecognizer?.addTarget(self, action: #selector(operatorWasSwiped(_ :)))
view4.swipeGestureRecognizer?.addTarget(self, action: #selector(operatorWasSwiped(_ :)))
view5.swipeGestureRecognizer?.addTarget(self, action: #selector(operatorWasSwiped(_ :)))

view1.tapGestureRecognizer?.addTarget(self, action: #selector(operatorWasSwiped(_ :)))
view2.tapGestureRecognizer?.addTarget(self, action: #selector(operatorWasSwiped(_ :)))
view3.tapGestureRecognizer?.addTarget(self, action: #selector(operatorWasSwiped(_ :)))
view4.tapGestureRecognizer?.addTarget(self, action: #selector(operatorWasSwiped(_ :)))
view5.tapGestureRecognizer?.addTarget(self, action: #selector(operatorWasSwiped(_ :)))

view1.addGestureRecognizer(view1.swipeGestureRecognizer!)
view2.addGestureRecognizer(view2.swipeGestureRecognizer!)
view3.addGestureRecognizer(view3.swipeGestureRecognizer!)
view4.addGestureRecognizer(view4.swipeGestureRecognizer!)
view.addGestureRecognizer(view5.swipeGestureRecognizer!)

view1.addGestureRecognizer(view1.tapGestureRecognizer!)
view2.addGestureRecognizer(view2.tapGestureRecognizer!)
view3.addGestureRecognizer(view3.tapGestureRecognizer!)
view4.addGestureRecognizer(view4.tapGestureRecognizer!)
view5.addGestureRecognizer(view5.tapGestureRecognizer!)

我添加的地方:

var swipeGestureRecognizer: UISwipeGestureRecognizer?
var tapGestureRecognizer: UITapGestureRecognizer?

为 OperationView 分类变量

这行得通,但它远非优雅(想象一下,如果我必须添加另一个视图......有点违背了我之前的抽象观点)

有什么想法吗?还是我错过了什么?

我正在使用 Swift 4Xcode 9

【问题讨论】:

您需要将对现有的HomeViewController 实例的引用传递给您的手势目标。您的目标当前是一次性实例。 我该怎么做? ViewControllers 很容易知道它们处理什么视图,但是就 MVC 而言,视图通常不知道哪个 ViewController 处理它们。你会建议什么方法? 【参考方案1】:

您正在方法内部创建该手势,并且该手势可能仅在调用该函数时存在于该范围内。所以从技术上讲,在你使用它之前就消失了。因此,在方法之外创建该手势的实例可能会在视图存在时存在。如果这有意义的话。

更新:正如 cmets 所指出的,我们确实需要父 viewController 的当前引用。

这样做怎么样..

class OperationView: UIView 

let swipeGestureRecognizer = UISwipeGestureRecognizer()
let tapGestureRecognizer = UITapGestureRecognizer()

override func awakeFromNib() 
    super.awakeFromNib()

    if let parentViewController = parentViewController 
    swipeGestureRecognizer.addTarget(parentViewController, action: #selector(HomeViewController.operatorWasSwiped(_:)))
    swipeGestureRecognizer.direction = .left

    tapGestureRecognizer.addTarget(parentViewController, action: #selector(HomeViewController.operatorWasSwiped(_:)))

    self.addGestureRecognizer(swipeGestureRecognizer)
    self.addGestureRecognizer(tapGestureRecognizer)
    

   


extension UIView 

var parentViewController: UIViewController? 
    var parentResponder: UIResponder? = self

    while parentResponder != nil 
        parentResponder = parentResponder!.next

        if let viewController = parentResponder as? UIViewController 
            return viewController
        
    
    return nil
   

【讨论】:

似乎仍然缺少对当前活动 HomeViewController 的引用。这对你有用吗? '因为它对我不起作用。 这个答案和原代码有同样的问题。它创建了HomeViewController 的无用实例作为每个手势的目标。 @J Arango,仍然让我觉得我已经把自己逼到了墙角,因为这看起来更像是一种黑客行为,而不是一种常规模式。这让我想重新评估我的架构。但是,这确实有效,所以谢谢你:) 是的,这是一个 hack 大声笑,有更好的方法可以做到这一点,但我不知道你是如何处理你的应用程序的架构的。一种方法是将所有视图添加到 IBOutlet 集合中,并通过它们进行交互,将每个视图添加到手势识别器中。这样就有了保存它们的 UIViewController 的引用。

以上是关于UIGestureRecognizer 不向其他类发送操作的主要内容,如果未能解决你的问题,请参考以下文章

从另一个类调用选择器的 UIGestureRecognizer

UIGestureRecognizer

UIGestureRecognizer,从另一个类调用选择器

UIGestureRecognizer

UIGestureRecognizer 目标问题

UIGestureRecognizer 中的 UIView 动画