点击手势动画UIView无法正常工作

时间:2016-03-14 21:53:27

标签: ios iphone swift uiview uitapgesturerecognizer

我在UILabel上有一个轻击手势,其翻译正在动画中。每当您在动画期间点击标签时,点击手势都没有响应。

这是我的代码:

    label.addGestureRecognizer(tapGesture)

    label.userInteractionEnabled = true
    label.transform = CGAffineTransformMakeTranslation(0, 0)

    UIView.animateWithDuration(12, delay: 0, options: UIViewAnimationOptions.AllowUserInteraction, animations: { () -> Void in
        label.transform = CGAffineTransformMakeTranslation(0, 900)
        }, completion: nil)

手势代码:

func setUpRecognizers() {
    tapGesture = UITapGestureRecognizer(target: self, action: "onTap:")
}
func onTap(sender : AnyObject) {
    print("Tapped")
}

有什么想法吗?谢谢:))

6 个答案:

答案 0 :(得分:2)

由于一个重要原因,您使用tapgesture后将无法完成您的目标。 tapgesture与标签的框架相关联。开始动画时,标签最终帧会立即更改,而您正在观看假电影(动画)。如果您能够在屏幕上触摸(0,900),则会在动画发生时正常触发。有一种方法可以做到这一点有点不同。最好的是使用touchesBegan。这是我刚刚编写的用于测试我的理论的扩展,但可以根据您的需要进行调整。例如,您可以使用实际的子类并访问标签属性而无需循环。

extension UIViewController{

public override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    guard let touch = touches.first else{return}
    let touchLocation = touch.locationInView(self.view)

    for subs in self.view.subviews{
        guard let ourLabel = subs as? UILabel else{return}
        print(ourLabel.layer.presentationLayer())

        if ourLabel.layer.presentationLayer()!.hitTest(touchLocation) != nil{
            print("Touching")
            UIView.animateWithDuration(0.4, animations: {
                self.view.backgroundColor = UIColor.redColor()
                }, completion: {
                    finished in
                    UIView.animateWithDuration(0.4, animations: {
                        self.view.backgroundColor = UIColor.whiteColor()
                        }, completion: {
                            finished in
                    })
                })
            }
        }

    }
}

你可以看到它正在测试CALayer.presentationLayer()的坐标。这就是我所说的电影。说实话,我仍然没有完全围绕表示层及其工作方式。

答案 1 :(得分:2)

我在这个问题上呆了好几个小时,不明白为什么点击不能在动画标签上起作用,而动画标签会在延迟3秒后滑出屏幕。

好说agibson007,关于动画的工作方式就像是假电影的播放,延迟3秒控制了电影的回报,但是动画一开始就没有延迟就改变了标签的帧。因此,点击(取决于标签在其原始位置的框架)将无法工作。

我的解决方案是将3秒延迟更改为超时功能,例如-

DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
   [weak self] in
   self?.hideLabel()           
}

这样可以在延迟期间保持轻拍工作,并允许在延迟之后在hideLabel()调用中运行动画。

答案 2 :(得分:1)

如果要查看动画,则需要将其放在onTap处理程序中。

let gesture = UITapGestureRecognizer(target: self, action: "onTap:")
gesture.numberOfTapsRequired = 1
label.addGestureRecognizer(gesture)
label.userInteractionEnabled = true

label.transform = CGAffineTransformMakeTranslation(0, 0)

UIView.animateWithDuration(12, delay: 3, options: [.AllowUserInteraction], animations: { () -> Void in
      label.transform = CGAffineTransformMakeTranslation(0, 900)
      }, completion: nil)


func onTap(sender : AnyObject)
{

    print("Tapped")
}

答案 3 :(得分:0)

要使您的点按手势有效,您必须设置点击次数。添加以下行:

tapGesture.numberOfTapsRequired = 1

(我假设tapGesture与您调用的label.addGestureRecognizer(tapGesture)相同

答案 4 :(得分:0)

以下是基于Swift 3中@ agibson007答案的更通用的答案。

这并没有立即解决我的问题,因为我有其他子视图覆盖了我的观点。如果遇到问题,请尝试更改扩展类型并为touchLocation编写print语句,以找出函数何时触发。接受的答案中的描述很好地解释了这个问题。

extension UIViewController {

    open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

        guard let touch = touches.first else { return }
        let touchLocation = touch.location(in: self.view)

        for subview in self.view.subviews {

            if subview.tag == VIEW_TAG_HERE && subview.layer.presentation()?.hitTest(touchLocation) != nil {

                print("[UIViewController] View Touched!")
                // Handle Action Here

            }

        }

    }

}

答案 5 :(得分:0)

如何在移动的视图中检测触摸

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

    let pf = layer.presentation()!.frame
    // note, that is in the space of our superview

    let p = self.convert(point, to: superview!)

    if pf.contains(p) { return self }
    return nil
}

就这么简单

相关提示-

不要忘记,在大多数情况下,如果正在运行动画,则几乎可以肯定要取消它。因此,假设有一个“移动目标”,并且您希望能够用手指抓住它并将其滑动到其他位置,那么在这种情况下,视图控制器中的代码自然就像..

   func sliderTouched() {
       if alreadyMoving {
          yourPropertyAnimator?.stopAnimation(true)
          yourPropertyAnimator = nil
       }
       etc ...
   }