简体   繁体   English

如何向 UIView 添加触摸事件?

[英]How to add a touch event to a UIView?

How do I add a touch event to a UIView?如何向 UIView 添加触摸事件?
I try:我尝试:

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:'

I don't want to create a subclass and overwrite我不想创建子类并覆盖

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

In iOS 3.2 and higher, you can use gesture recognizers.在 iOS 3.2 及更高版本中,您可以使用手势识别器。 For example, this is how you would handle a tap event:例如,这是您处理点击事件的方式:

//The setup code (in viewDidLoad in your view controller)
UITapGestureRecognizer *singleFingerTap = 
  [[UITapGestureRecognizer alloc] initWithTarget:self 
                                          action:@selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleFingerTap];

//The event handling method
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer
{
  CGPoint location = [recognizer locationInView:[recognizer.view superview]];

  //Do stuff here...
}

There are a bunch of built in gestures as well.还有一堆内置的手势。 Check out the docs for iOS event handling and UIGestureRecognizer .查看 iOS 事件处理和UIGestureRecognizer的文档。 I also have a bunch of sample code up on github that might help.我在github上还有一堆示例代码可能会有所帮助。

Gesture Recognizers手势识别器

There are a number of commonly used touch events (or gestures) that you can be notified of when you add a Gesture Recognizer to your view.当您将手势识别器添加到视图时,您会收到许多常用的触摸事件(或手势)的通知。 They following gesture types are supported by default:默认支持以下手势类型:

  • UITapGestureRecognizer Tap (touching the screen briefly one or more times) UITapGestureRecognizer Tap (短暂触摸屏幕一次或多次)
  • UILongPressGestureRecognizer Long touch (touching the screen for a long time) UILongPressGestureRecognizer Long touch长时间触摸屏幕)
  • UIPanGestureRecognizer Pan (moving your finger across the screen) UIPanGestureRecognizer Pan (在屏幕上移动手指)
  • UISwipeGestureRecognizer Swipe (moving finger quickly) UISwipeGestureRecognizer Swipe (快速移动手指)
  • UIPinchGestureRecognizer Pinch (moving two fingers together or apart - usually to zoom) UIPinchGestureRecognizer(两个手指移动在一起或分开-通常进行缩放)
  • UIRotationGestureRecognizer Rotate (moving two fingers in a circular direction) UIRotationGestureRecognizer Rotate (沿圆周方向移动两个手指)

In addition to these, you can also make your own custom gesture recognizer.除了这些,您还可以制作自己的自定义手势识别器。

Adding a Gesture in the Interface Builder在界面生成器中添加手势

Drag a gesture recognizer from the object library onto your view.将手势识别器从对象库拖到您的视图上。

在此处输入图片说明

Control drag from the gesture in the Document Outline to your View Controller code in order to make an Outlet and an Action.控制从文档大纲中的手势拖动到您的视图控制器代码,以制作一个插座和一个动作。

在此处输入图片说明

This should be set by default, but also make sure that User Action Enabled is set to true for your view.这应该是默认设置,但也要确保用户操作已启用为您的视图设置为 true。

在此处输入图片说明

Adding a Gesture Programmatically以编程方式添加手势

To add a gesture programmatically, you (1) create a gesture recognizer, (2) add it to a view, and (3) make a method that is called when the gesture is recognized.要以编程方式添加手势,您 (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")
    }
}

Notes笔记

  • The sender parameter is optional. sender参数是可选的。 If you don't need a reference to the gesture then you can leave it out.如果您不需要对手势的引用,则可以将其省略。 If you do so, though, remove the (sender:) after the action method name.但是,如果您这样做,请删除操作方法名称后面的(sender:)
  • The naming of the handleTap method was arbitrary. handleTap方法的命名是任意的。 Name it whatever you want using action: #selector( someMethodName (sender:)) .使用action: #selector( someMethodName (sender:))其命名为您想要的任何名称。

More Examples更多例子

You can study the gesture recognizers that I added to these views to see how they work.您可以研究我添加到这些视图中的手势识别器,看看它们是如何工作的。

在此处输入图片说明

Here is the code for that project:这是该项目的代码:

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
        }
    }
}

Notes笔记

  • 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.我上面的示例的已知问题:(1) 平移视图在下一个手势事件时重置其框架。 (2) Swipe view comes from the wrong direction on the first swipe. (2) 第一次滑动时,滑动视图来自错误的方向。 (These bugs in my examples should not affect your understanding of how Gestures Recognizers work, though.) (不过,我示例中的这些错误不应该影响您对手势识别器工作方式的理解。)

I think you can simply use我认为你可以简单地使用

UIControl *headerView = ...
[headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown];

i mean headerView extends from UIControl.我的意思是 headerView 从 UIControl 扩展。

Swift 3 & Swift 4斯威夫特 3 和斯威夫特 4

import UIKit

extension UIView {
  func addTapGesture(tapNumber: Int, target: Any, action: Selector) {
    let tap = UITapGestureRecognizer(target: target, action: action)
    tap.numberOfTapsRequired = tapNumber
    addGestureRecognizer(tap)
    isUserInteractionEnabled = true
  }
}

Use使用

yourView.addTapGesture(tapNumber: 1, target: self, action: #selector(yourMethod))

Based on the accepted answer you can define a macro:根据接受的答案,您可以定义一个宏:

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

This macro uses ARC, so there's no release call.这个宏使用 ARC,所以没有release调用。

Macro usage example:宏使用示例:

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

In Swift 4.2 and Xcode 10Swift 4.2和 Xcode 10 中

Use UITapGestureRecognizer for to add touch event使用UITapGestureRecognizer添加触摸事件

//Add tap gesture to your view
let tap = UITapGestureRecognizer(target: self, action: #selector(handleGesture))
yourView.addGestureRecognizer(tap)

// GestureRecognizer
@objc func handleGesture(gesture: UITapGestureRecognizer) -> Void {
//Write your code here
}

If you want to use SharedClass如果你想使用SharedClass

//This is my shared class
import UIKit

class SharedClass: NSObject {

    static let sharedInstance = SharedClass()

    //Tap gesture function
    func addTapGesture(view: UIView, target: Any, action: Selector) {
        let tap = UITapGestureRecognizer(target: target, action: action)
        view.addGestureRecognizer(tap)
    }
} 

I have 3 views in my ViewController called view1, view2 and view3.我的 ViewController 中有 3 个视图,分别称为 view1、view2 和 view3。

override func viewDidLoad() {
    super.viewDidLoad()
    //Add gestures to your views
    SharedClass.sharedInstance.addTapGesture(view: view1, target: self, action: #selector(handleGesture))
    SharedClass.sharedInstance.addTapGesture(view: view2, target: self, action: #selector(handleGesture))
    SharedClass.sharedInstance.addTapGesture(view: view3, target: self, action: #selector(handleGesture2))

}

// GestureRecognizer
@objc func handleGesture(gesture: UITapGestureRecognizer) -> Void {
    print("printed 1&2...")
}
// GestureRecognizer
@objc func handleGesture2(gesture: UITapGestureRecognizer) -> Void {
    print("printed3...")
}

You can achieve this by adding Gesture Recogniser in your code.您可以通过在代码中添加手势识别器来实现这一点。

Step 1: ViewController.m:第 1 步: ViewController.m:

// Declare the Gesture.
UITapGestureRecognizer *gesRecognizer = [[UITapGestureRecognizer alloc] 
                                          initWithTarget:self 
                                          action:@selector(handleTap:)];
gesRecognizer.delegate = self;

// Add Gesture to your view.
[yourView addGestureRecognizer:gesRecognizer]; 

Step 2: ViewController.m:第 2 步: ViewController.m:

// Declare the Gesture Recogniser handler method.
- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer{
   NSLog(@"Tapped");
}

NOTE: here yourView in my case was @property (strong, nonatomic) IBOutlet UIView *localView;注意:这里 yourView 在我的例子中是 @property @property (strong, nonatomic) IBOutlet UIView *localView;

EDIT: *localView is the white box in Main.storyboard from below编辑: *localView 是 Main.storyboard 从下面的白框

在此处输入图片说明

在此处输入图片说明

Heres a Swift version:这是一个 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
    }
}

Swift 3:斯威夫特 3:

let tapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGestureRecognizer(_:)))
view.addGestureRecognizer(tapGestureRecognizer)

func handleTapGestureRecognizer(_ gestureRecognizer: UITapGestureRecognizer) {

}

Seems quite simple these days.这些天似乎很简单。 This is the Swift version.这是斯威夫特版本。

let tap = UITapGestureRecognizer(target: self, action: #selector(viewTapped))
    view.addGestureRecognizer(tap)

@objc func viewTapped(recognizer: UIGestureRecognizer)
{
    //Do what you need to do!
}

Objective-C:目标-C:

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

Swift:斯威夫特:

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

The question asks:问题问:

How do I add a touch event to a UIView?如何向 UIView 添加触摸事件?

It isn't asking for a tap event.它不是要求点击事件。

Specifically OP wants to implement UIControlEventTouchDown具体OP想要实现UIControlEventTouchDown

Switching the UIView to UIControl is the right answer here because Gesture Recognisers don't know anything about .touchDown , .touchUpInside , .touchUpOutside etc.UIView切换到UIControl是正确的答案,因为Gesture Recognisers.touchDown.touchUpInside.touchUpOutside.touchUpOutside

Additionally, UIControl inherits from UIView so you're not losing any functionality.此外,UIControl 继承自 UIView,因此您不会丢失任何功能。

If all you want is a tap, then you can use the Gesture Recogniser.如果您只需要轻按一下,那么您可以使用手势识别器。 But if you want finer control, like this question asks for, you'll need UIControl.但是如果你想要更好的控制,就像这个问题所要求的那样,你将需要 UIControl。

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

Here is ios tapgesture;这是 ios tapgesture; First you need to create action for GestureRecognizer after write the below code under the action as shown below首先,您需要在动作下编写以下代码后为 GestureRecognizer 创建动作,如下所示

- (IBAction)tapgesture:(id)sender

{


[_password resignFirstResponder];


[_username resignFirstResponder];

NSLog(@" TapGestureRecognizer  tapped");

}

Another way is adding a transparent button to the view另一种方法是在视图中添加一个透明按钮

UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom];
b.frame = CGRectMake(0, 0, headerView.width, headerView.height);
[headerView addSubview:b];
[b addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchDown];

And then, handle click:然后,处理点击:

- (void)buttonClicked:(id)sender
{}

Create a gesture recognizer (subclass), that will implement touch events, like touchesBegan .创建一个手势识别器(子类),它将实现触摸事件,如touchesBegan You can add it to the view after that.之后您可以将其添加到视图中。

This way you'll use composition instead subclassing (which was the request).这样,您将使用组合而不是子类化(这是请求)。

Why don't you guys try SSEventListener ?你们为什么不试试SSEventListener

You don't need to create any gesture recognizer and separate your logic apart to another method.您不需要创建任何手势识别器并将您的逻辑分开到另一种方法。 SSEventListener supports setting listener blocks on a view to listen for single tap gesture, double tap gesture and N-tap gesture if you like, and long press gesture. SSEventListener支持在视图上设置侦听器块以侦听单击手势、双击手势和 N-tap 手势(如果您愿意)以及长按手势。 Setting a single tap gesture listener becomes this way:设置单击手势监听器变成这样:

[view ss_addTapViewEventListener:^(UITapGestureRecognizer *recognizer) { ... } numberOfTapsRequired:1];

Swift 5.3斯威夫特 5.3

Solution with Closure, based on: UIGestureRecognizer with closure带闭包的解决方案,基于: UIGestureRecognizer with closure

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
    }
}

Using:使用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM