我如何添加一个触摸事件到一个UIView? 我试一试:

UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, nextY)] autorelease];
[headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown];
// ERROR MESSAGE: UIView may not respond to '-addTarget:action:forControlEvents:'

我不想创建一个子类然后重写

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

当前回答

objective - c:

UIControl *headerView = [[UIControl alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, nextY)];
[headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown];

迅速:

let headerView = UIControl(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: nextY))
headerView.addTarget(self, action: #selector(myEvent(_:)), for: .touchDown)

问题是:

我如何添加一个触摸事件到一个UIView?

它并不是在请求一个点击事件。

特别是OP想要实现UIControlEventTouchDown

切换UIView到UIControl是正确的答案,因为手势识别器不知道。touchdown。touchupinside,。touchupoutside等等。

此外,UIControl继承自UIView,所以你不会失去任何功能。

如果你想要的只是轻敲一下,那么你可以使用手势识别器。但如果你想要更好的控制,就像这个问题要求的,你需要UIControl。

https://developer.apple.com/documentation/uikit/uicontrol?language=objc https://developer.apple.com/documentation/uikit/uigesturerecognizer?language=objc

其他回答

斯威夫特5.3

基于闭包的UIGestureRecognizer解决方案

final class BindableGestureRecognizer: UITapGestureRecognizer {
    private var action: () -> Void

    init(action: @escaping () -> Void) {
        self.action = action
        super.init(target: nil, action: nil)
        self.addTarget(self, action: #selector(execute))
    }

    @objc private func execute() {
        action()
    }
}

public extension UIView {
    /// A discrete gesture recognizer that interprets single or multiple taps.
    /// - Parameters:
    ///   - tapNumber: The number of taps necessary for gesture recognition.
    ///   - closure: A selector that identifies the method implemented by the target to handle the gesture recognized by the receiver. The action selector must conform to the signature described in the class overview. NULL is not a valid value.
    func addTapGesture(tapNumber: Int = 1, _ closure: (() -> Void)?) {
        guard let closure = closure else { return }

        let tap = BindableGestureRecognizer(action: closure)
        tap.numberOfTapsRequired = tapNumber
        addGestureRecognizer(tap)

        isUserInteractionEnabled = true
    }
}

使用:

view.addTapGesture { [weak self] in
    self?.view.backgroundColor = .red
}

手势识别器

有许多常用的触摸事件(或手势),当你添加一个手势识别器到你的视图时,你可以得到通知。默认支持以下手势类型:

UITapGestureRecognizer轻触(简单触摸屏幕一次或多次) UILongPressGestureRecognizer长触(长时间触屏) UIPanGestureRecognizer Pan(在屏幕上移动手指) 滑动(快速移动手指) UIPinchGestureRecognizer捏(将两个手指放在一起或分开-通常是缩放) UIRotationGestureRecognizer旋转(沿圆周方向移动两个手指)

除此之外,你还可以制作自己的手势识别器。

在接口生成器中添加一个手势

将一个手势识别器从对象库拖到视图上。

控件从文档大纲中的手势拖到视图控制器代码中,以创建Outlet和Action。

这应该在默认情况下设置,但也要确保为视图将User Action Enabled设置为true。

以编程方式添加手势

要以编程方式添加一个手势,你(1)创建一个手势识别器,(2)将它添加到视图中,(3)创建一个方法,当手势被识别时调用该方法。

import UIKit
class ViewController: UIViewController {

    @IBOutlet weak var myView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 1. create a gesture recognizer (tap gesture)
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(sender:)))
        
        // 2. add the gesture recognizer to a view
        myView.addGestureRecognizer(tapGesture)
    }
    
    // 3. this method is called when a tap is recognized
    @objc func handleTap(sender: UITapGestureRecognizer) {
        print("tap")
    }
}

笔记

sender参数为可选参数。如果你不需要一个手势的引用,那么你可以把它去掉。如果你这样做,但是,删除(sender:)后的动作方法名称。 handleTap方法的命名是任意的。使用action: #selector(someMethodName(sender:))将其命名为任何您想要的名称。

更多的例子

您可以研究我添加到这些视图中的手势识别器,以了解它们是如何工作的。

下面是该项目的代码:

import UIKit
class ViewController: UIViewController {
    
    @IBOutlet weak var tapView: UIView!
    @IBOutlet weak var doubleTapView: UIView!
    @IBOutlet weak var longPressView: UIView!
    @IBOutlet weak var panView: UIView!
    @IBOutlet weak var swipeView: UIView!
    @IBOutlet weak var pinchView: UIView!
    @IBOutlet weak var rotateView: UIView!
    @IBOutlet weak var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Tap
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))
        tapView.addGestureRecognizer(tapGesture)
        
        // Double Tap
        let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
        doubleTapGesture.numberOfTapsRequired = 2
        doubleTapView.addGestureRecognizer(doubleTapGesture)
        
        // Long Press
        let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(gesture:)))
        longPressView.addGestureRecognizer(longPressGesture)
        
        // Pan
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(gesture:)))
        panView.addGestureRecognizer(panGesture)
        
        // Swipe (right and left)
        let swipeRightGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(gesture:)))
        let swipeLeftGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(gesture:)))
        swipeRightGesture.direction = UISwipeGestureRecognizerDirection.right
        swipeLeftGesture.direction = UISwipeGestureRecognizerDirection.left
        swipeView.addGestureRecognizer(swipeRightGesture)
        swipeView.addGestureRecognizer(swipeLeftGesture)
        
        // Pinch
        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(gesture:)))
        pinchView.addGestureRecognizer(pinchGesture)
        
        // Rotate
        let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(handleRotate(gesture:)))
        rotateView.addGestureRecognizer(rotateGesture)
        
    }
    
    // Tap action
    @objc func handleTap() {
        label.text = "Tap recognized"
        
        // example task: change background color
        if tapView.backgroundColor == UIColor.blue {
            tapView.backgroundColor = UIColor.red
        } else {
            tapView.backgroundColor = UIColor.blue
        }
        
    }
    
    // Double tap action
    @objc func handleDoubleTap() {
        label.text = "Double tap recognized"
        
        // example task: change background color
        if doubleTapView.backgroundColor == UIColor.yellow {
            doubleTapView.backgroundColor = UIColor.green
        } else {
            doubleTapView.backgroundColor = UIColor.yellow
        }
    }
    
    // Long press action
    @objc func handleLongPress(gesture: UILongPressGestureRecognizer) {
        label.text = "Long press recognized"
        
        // example task: show an alert
        if gesture.state == UIGestureRecognizerState.began {
            let alert = UIAlertController(title: "Long Press", message: "Can I help you?", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        }
    }
    
    // Pan action
    @objc func handlePan(gesture: UIPanGestureRecognizer) {
        label.text = "Pan recognized"
        
        // example task: drag view
        let location = gesture.location(in: view) // root view
        panView.center = location
    }
    
    // Swipe action
    @objc func handleSwipe(gesture: UISwipeGestureRecognizer) {
        label.text = "Swipe recognized"
        
        // example task: animate view off screen
        let originalLocation = swipeView.center
        if gesture.direction == UISwipeGestureRecognizerDirection.right {
            UIView.animate(withDuration: 0.5, animations: {
                self.swipeView.center.x += self.view.bounds.width
            }, completion: { (value: Bool) in
                self.swipeView.center = originalLocation
            })
        } else if gesture.direction == UISwipeGestureRecognizerDirection.left {
            UIView.animate(withDuration: 0.5, animations: {
                self.swipeView.center.x -= self.view.bounds.width
            }, completion: { (value: Bool) in
                self.swipeView.center = originalLocation
            })
        }
    }
    
    // Pinch action
    @objc func handlePinch(gesture: UIPinchGestureRecognizer) {
        label.text = "Pinch recognized"
        
        if gesture.state == UIGestureRecognizerState.changed {
            let transform = CGAffineTransform(scaleX: gesture.scale, y: gesture.scale)
            pinchView.transform = transform
        }
    }
    
    // Rotate action
    @objc func handleRotate(gesture: UIRotationGestureRecognizer) {
        label.text = "Rotate recognized"
        
        if gesture.state == UIGestureRecognizerState.changed {
            let transform = CGAffineTransform(rotationAngle: gesture.rotation)
            rotateView.transform = transform
        }
    }
}

笔记

You can add multiple gesture recognizers to a single view. For the sake of simplicity, though, I didn't do that (except for the swipe gesture). If you need to for your project, you should read the gesture recognizer documentation. It is fairly understandable and helpful. Known issues with my examples above: (1) Pan view resets its frame on next gesture event. (2) Swipe view comes from the wrong direction on the first swipe. (These bugs in my examples should not affect your understanding of how Gestures Recognizers work, though.)

简单实用的扩展:

extension UIView {
private struct OnClickHolder {
    static var _closure:()->() = {}
}

private var onClickClosure: () -> () {
    get { return OnClickHolder._closure }
    set { OnClickHolder._closure = newValue }
}

func onTap(closure: @escaping ()->()) {
    self.onClickClosure = closure
    
    isUserInteractionEnabled = true
    let tap = UITapGestureRecognizer(target: self, action: #selector(onClickAction))
    addGestureRecognizer(tap)
}

@objc private func onClickAction() {
    onClickClosure()
}

}

用法:

    override func viewDidLoad() {
    super.viewDidLoad()
    let view = UIView(frame: .init(x: 0, y: 0, width: 80, height: 50))
    view.backgroundColor  = .red
    view.onTap {
        print("View Tapped")
    }
}

基于已接受的答案,你可以定义一个宏:

#define handle_tap(view, delegate, selector) do {\
    view.userInteractionEnabled = YES;\
    [view addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget:delegate action:selector]];\
} while(0)

这个宏使用ARC,所以没有发布调用。

宏使用示例:

handle_tap(userpic, self, @selector(onTapUserpic:));

以下是Swift版本:

// MARK: Gesture Extensions
extension UIView {

    func addTapGesture(#tapNumber: Int, target: AnyObject, action: Selector) {
        let tap = UITapGestureRecognizer (target: target, action: action)
        tap.numberOfTapsRequired = tapNumber
        addGestureRecognizer(tap)
        userInteractionEnabled = true
    }

    func addTapGesture(#tapNumber: Int, action: ((UITapGestureRecognizer)->())?) {
        let tap = BlockTap (tapCount: tapNumber, fingerCount: 1, action: action)
        addGestureRecognizer(tap)
        userInteractionEnabled = true
    }
}