在一个可以略微离开屏幕的正在运行的animation中检索轻敲的UIButton

这是下面的代码:

在这里输入图像说明

码:

import UIKit class TornadoButton: UIButton{ override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let pres = self.layer.presentation()! let suppt = self.convert(point, to: self.superview!) let prespt = self.superview!.layer.convert(suppt, to: pres) return super.hitTest(prespt, with: event) } } class TestViewController: UIViewController{ override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let greySubview = UIView() greySubview.backgroundColor = .red greySubview.translatesAutoresizingMaskIntoConstraints = false self.view.addSubview(greySubview) greySubview.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true greySubview.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true greySubview.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true greySubview.heightAnchor.constraint(equalTo: greySubview.widthAnchor).isActive = true let button = TornadoButton() greySubview.addSubview(button) button.translatesAutoresizingMaskIntoConstraints = false button.widthAnchor.constraint(equalTo: greySubview.widthAnchor, multiplier: 0.09).isActive = true button.heightAnchor.constraint(equalTo: greySubview.heightAnchor, multiplier: 0.2).isActive = true //below constrains are needed, else the origin of the UIBezierPath is wrong button.centerXAnchor.constraint(equalTo: greySubview.centerXAnchor).isActive = true button.centerYAnchor.constraint(equalTo: greySubview.centerYAnchor, constant: self.view.frame.height * 0.35).isActive = true self.view.layoutIfNeeded() let orbit = CAKeyframeAnimation(keyPath: "position") button.addTarget(self, action: #selector(tappedOnCard(_:)), for: .touchUpInside) let circlePath = UIBezierPath(arcCenter: greySubview.frame.origin, radius: CGFloat(greySubview.frame.width * 0.5), startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true) orbit.duration = 12 orbit.path = circlePath.cgPath orbit.isAdditive = true orbit.repeatCount = Float.greatestFiniteMagnitude orbit.calculationMode = kCAAnimationPaced orbit.rotationMode = kCAAnimationRotateAuto button.layer.add(orbit, forKey: "orbit") button.backgroundColor = .blue let gr = UITapGestureRecognizer(target: self, action: #selector(onTap(gesture:))) greySubview.addGestureRecognizer(gr) } @objc func onTap(gesture:UITapGestureRecognizer) { let p = gesture.location(in: gesture.view) let v = gesture.view?.hitTest(p, with: nil) } @IBAction func tappedOnCard(_ sender: UIButton){ print(sender) } } 

这几乎可以工作,但是:

如果button在屏幕上100%可见,我可以检索button。 如果是,例如,50%可见(和50%的屏幕(看下面的图片)),我不检索button水龙头(又名检索打印)。

如何在运行中的animation中检索button,并且可以稍微离开屏幕?

在这里输入图像说明

原始答案:

在greySubview中的UITapGestureRecognizer很可能是消耗了触摸,而不是让它通过button。 尝试这个:

 gr.cancelsTouchesInView = NO; 

在将UITapGestureRecognizer添加到greySubview之前。


编辑答案:

如果你这样做,请忽略我以前的回答,然后恢复变更。 我原来的答案是没有意义的,因为在你的情况下,button是grayView视图的子视图和cancelsTouchesInView视图向上视图层次结构,而不是向下。

经过大量的挖掘,我能够弄清楚为什么会发生这种情况。 这是因为TornadoButton在animation中的命中testing不正确。 由于您正在为button设置animation,因此您需要重写TornadoButtonhitTestTornadoButton方法,以便在命中testing时代替animation位置而不是button的实际位置。

pointInside方法的默认实现不考虑button的animation表示层,只是试图检查矩形内的触摸点(由于触摸在其他地方,将失败)。

这些方法的下列实现似乎可以做到这一点:

 class TornadoButton: UIButton{ override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let pres = self.layer.presentation()! let suppt = self.convert(point, to: self.superview!) let prespt = self.superview!.layer.convert(suppt, to: pres) if (pres.hitTest(suppt)) != nil{ return self } return super.hitTest(prespt, with: event) } override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { let pres = self.layer.presentation()! let suppt = self.convert(point, to: self.superview!) return (pres.hitTest(suppt)) != nil } } 

我不明白,为什么你使用button来显示一个简单的矩形时,视图也可以工作,但无论如何…你没有告诉我们你的目标添加到你的button。

 button.addTarget(self, action: #selector(ViewController.buttonPressed(_:)), for: .touchUpInside) // This is needed that your button 'does something' button.tag = 1 // This is a tag that you can use to identify which button has been pressed 

与functionbuttonPressed看起来像这样:

 @objc func buttonPressed(_ button: UIButton) { switch button.tag { case 1: print("First button was pressed") case 2: print("Second button was pressed") default: print("I don't know the button you pressed") } }