iOS检测UIView的点击和触摸事件

43

我卡在一个问题上,需要确定如何检测UIView被按下和UIView被轻击。当它被按下时,我想让UIView更改其背景颜色。当它被点击时,我想让UIView执行某些任务。我想知道如何解决这个问题。

-(void)viewDidLoad
{        
    UITapGestureRecognizer *dismissGestureRecognition = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDismissDoubleTap:)];
    dismissGestureRecognition.numberOfTapsRequired = 1;
    [sectionDismissDoubleView addGestureRecognizer:dismissGestureRecognition];

    UITapGestureRecognizer *dismissGestureDownRecognition = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissGestureDownRecognition:)];
    dismissGestureRecognition.numberOfTouchesRequired = 1;
    [sectionDismissDoubleView addGestureRecognizer:dismissGestureDownRecognition];
}

- (void)handleDismissDoubleTap:(UIGestureRecognizer*)tap {
    SettingsDismissDoubleViewController *settingsDouble = [[SettingsDismissDoubleViewController alloc] initWithNibName:@"SettingsDismissDoubleViewController" bundle:nil];
    [self.navigationController pushViewController:settingsDouble animated:YES];
}

- (void)dismissGestureDownRecognition:(UIGestureRecognizer*)tap {
    NSLog(@"Down");
}
5个回答

64

在此输入图片描述

这种方法不需要子类化任何内容。您只需将 UILongPressGestureRecognizer 添加到视图中,并将 minimumPressDuration 设置为零。然后在手势事件被调用时检查状态,以查看触摸事件是开始还是结束。

以下是上面示例图片的整个项目代码。

import UIKit
class ViewController: UIViewController {
    @IBOutlet weak var myView: UIView!
    override func viewDidLoad() {
        super.viewDidLoad()
        let tap = UILongPressGestureRecognizer(target: self, action: #selector(tapHandler))
        tap.minimumPressDuration = 0
        myView.addGestureRecognizer(tap)
    }

    @objc func tapHandler(gesture: UITapGestureRecognizer) {
        
        // there are seven possible events which must be handled

        if gesture.state == .began {
            myView.backgroundColor = UIColor.darkGray
            return
        }

        if gesture.state == .changed {
            print("very likely, just that the finger wiggled around while the user was holding down the button. generally, just ignore this")
            return
        }

        if gesture.state == .possible || gesture.state == .recognized {
            print("in almost all cases, simply ignore these two, unless you are creating very unusual custom subclasses")
            return
        }

        // the three remaining states are
        // .cancelled, .failed, and .ended
        // in all three cases, must return to the normal button look:
        myView.backgroundColor = UIColor.lightGray
    }
}

感谢这篇回答提供灵感。


10
这将防止父级滚动视图滚动。 - xleon
迄今为止最好的答案(像Suragch一样,通常如此!) - Fattie
太棒了!正是我所需要的。 - CatBrownie
太棒了!也许可以加一些关于它如何工作的评论。 :) - Sentry.co
1
各位注意了,你们还需要处理 .cancelled.failed - Fattie
显示剩余6条评论

49

对于你想要做的事情来说,手势识别器可能有点过头了。你可能只需要结合使用 -touchesBegan:withEvent:-touchesEnded:withEvent:

这个方法存在缺陷,但它应该能够让你了解你想要做什么。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    self.touchDown = YES;
    self.backgroundColor = [UIColor redColor];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    // Triggered when touch is released
    if (self.isTouchDown) {
        self.backgroundColor = [UIColor whiteColor];
        self.touchDown = NO;
    }
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    // Triggered if touch leaves view
    if (self.isTouchDown) {
        self.backgroundColor = [UIColor whiteColor];
        self.touchDown = NO;
    }
}

这段代码应该放在您创建的自定义UIView子类中。然后使用此自定义视图类型,而不是UIView,您将获得触摸处理功能。


1
通过对UIView进行子类化实现滚动视图是保持父视图可滚动的好方法。 - Justin Vallely

6

在每个UIControl子类(UIButton等)中,您可以使用此功能订阅特定的UIControlEvent集合:

addTarget:action:forControlEvents

对于UIControlEventTouchDown事件,您应该使用适当的选择器添加目标;对于UIControlEventTouchUpInside事件,您需要另外添加目标/选择器。

UIControl参考文档


9
问题是关于UIView而不是UIControl。 - trickster77777

4

感谢Holly的回答,我建立了一个ButtonView便捷类。

编辑:如此答案所述,UILongPressGestureRecognizer反应更快,因此我更新了我的类。

用法:

let btn = ButtonView()
btn.onNormal = { btn.backgroundColor = .clearColor() }
btn.onPressed = { btn.backgroundColor = .blueColor() }
btn.onReleased = yourAction // Function to be called

类:

/** View that can be pressed like a button */

import UIKit

class ButtonView : UIView {

    /* Called when the view goes to normal state (set desired appearance) */
    var onNormal = {}
    /* Called when the view goes to pressed state (set desired appearance) */
    var onPressed = {}
    /* Called when the view is released (perform desired action) */
    var onReleased = {}

    override init(frame: CGRect)
    {
        super.init(frame: frame)

        let recognizer = UILongPressGestureRecognizer(target: self, action: Selector("touched:"))
        recognizer.delegate = self
        recognizer.minimumPressDuration = 0.0
        addGestureRecognizer(recognizer)
        userInteractionEnabled = true

        onNormal()
    }

    func touched(sender: UILongPressGestureRecognizer)
    {
        if sender.state == .Began {
            onPressed(self)
        } else if sender.state == .Ended {
            onNormal(self)
            onReleased()
        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

我终于改用了一个使用UIControl的版本,它反应不那么快,但有其他优点:如果您在按钮上方拖动,则可以在下面拖动UIScrollView。这样,当您尝试拖动时,滚动视图不会被卡住,并且您的拖动手势从按钮所在的位置开始。 - Ferran Maylinch

1
首先,通过您的选择器handleDismissDoubleTap:,我假设您正在寻找双击以解除。要实现这一点,您应该执行以下操作:dismissGestureRecognition.numberOfTapsRequired = 2; 其次,如果您所说的触摸是指一种长按(或“按住并保持”)的手势,您应该使用UILongPressGestureRecognizer而不是UITapGestureRecognizer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接