【问题标题】:How to add a touch event to a UIView?如何向 UIView 添加触摸事件?
【发布时间】:2011-06-07 07:38:20
【问题描述】:

如何向 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

【问题讨论】:

标签: ios objective-c events uiview touch


【解决方案1】:

在 iOS 3.2 及更高版本中,您可以使用手势识别器。例如,这是您处理点击事件的方式:

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

还有很多内置的手势。查看有关 iOS 事件处理和 UIGestureRecognizer 的文档。我在github 上还有一堆示例代码可能会有所帮助。

【讨论】:

  • 但这会覆盖视图的触摸默认操作。 ¿ 是否可以调用视图的默认触摸操作?像 [super touchesBegan] 之类的东西?...
  • CGPoint 线有什么作用?
  • @yourfriendzak CGPoint 表示在被点击视图的超级视图中点击的位置。您可以使用该点将点击视图(或同级视图)移动到点击位置。这在UIPanGestureRecognizer 的处理程序中更有用,用于在屏幕上拖动视图。
  • 非常简洁的答案,谢谢。但是,天哪,如果这更容易一点会不会很好?! :)
  • 还不错,但我希望有像 github.com/neror/ftutils/blob/master/Headers/FTUtils/… 这样的基于块的 API。 Xcode 4 也支持在 Interface Builder 中添加/配置手势识别器。
【解决方案2】:

我认为你可以简单地使用

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

我的意思是 headerView 是从 UIControl 扩展而来的。

【讨论】:

  • 这是更好的答案。 UITapGestureRecognizer 不能替代 UIControlEventTouchDownTap 通常由 UIControlEventTouchDownUIControlEventTouchUpInside 组成。
  • A UIView 不是 UIControl,因此无权访问 addTarget:action:forControlEvents:
  • 还要注意 UIControl 继承自 UIView。为了我的目的,我所要做的就是简单地切换子类类型。
  • 您可以将其类设置为 UIControl @RobertJoseph .. 转到 xib 文件并将 View Custom 类设置为 UIControl 。现在你可以在其中处理事件了..
  • 既然我改变继承只是为了处理水龙头,为什么这又是一个更好的解决方案呢?
【解决方案3】:

基于accepted answer你可以定义一个宏:

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

此宏使用 ARC,因此没有 release 调用。

宏用法示例:

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

【讨论】:

  • 如果您在storyboard中创建视图,别忘了启用“用户交互启用”选项。
  • 我们应该在哪里定义 .h 或 .m 中的宏以及参数的名称应该是什么。我的意思是#define handle_tap(UIView view,Delegate delegate, SEL selector)do..
【解决方案4】:

您可以通过在代码中添加手势识别器来实现此目的。

第 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]; 

第 2 步: ViewController.m:

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

注意:这里 yourView 在我的情况下是@property (strong, nonatomic) IBOutlet UIView *localView;

编辑: *localView 是 Main.storyboard 下面的白框

【讨论】:

  • 我有多个视图,所以我可以发送发件人 ID 吗??
  • 你必须去内部子视图,然后你可以作为发送者。---------for (UIView *view in self.topicScrollView.subviews) {//去里面superview if ([view isKindOfClass:[UIButton class]]) { // 转到那个特定的视图 // 在这里你已经到达了那个点。 } }
【解决方案5】:

这是一个 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
    }
}

【讨论】:

【解决方案6】:

手势识别器

当您将Gesture Recognizer 添加到您的视图时,可以通知您一些常用的触摸事件(或手势)。默认支持以下手势类型:

  • UITapGestureRecognizer 点击(短按屏幕一次或多次)
  • UILongPressGestureRecognizer长按(长时间触摸屏幕)
  • UIPanGestureRecognizer Pan(在屏幕上移动手指)
  • UISwipeGestureRecognizer 滑动(快速移动手指)
  • UIPinchGestureRecognizer 捏合(将两根手指合拢或分开——通常用于缩放)
  • UIRotationGestureRecognizer 旋转(两个手指在圆周方向移动)

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

在界面生成器中添加手势

将手势识别器从对象库拖到您的视图中。

控制从文档大纲中的手势拖动到您的视图控制器代码,以制作一个 Outlet 和一个动作。

这应该默认设置,但也要确保 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(<strong>someMethodName</strong>(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
        }
    }
}

备注

  • 您可以将多个手势识别器添加到单个视图中。不过,为了简单起见,我没有这样做(滑动手势除外)。如果你的项目需要,你应该阅读gesture recognizer documentation。这很容易理解,也很有帮助。
  • 上述示例的已知问题:(1) 平移视图在下一个手势事件时重置其框架。 (2) 滑动视图在第一次滑动时来自错误的方向。 (不过,我的示例中的这些错误不会影响您对手势识别器工作原理的理解。)

【讨论】:

  • 您的回答非常好,对详细描述很有帮助。这就是为什么我投票赞成你也回答。但是您只是错过了一条说明,我认为您必须在回答中包含该说明,因为您已对其进行了详细解释。该指令是关于设置“.EnableUserInteraction = TRUE”。我希望你同意我的看法。
  • 为了在UIView 上进行这项工作,您还需要添加:self.isUserInteractionEnabled = true;
  • 我有一个视图,只要点击一个视图,我就在其中实现了 DropMenu。当我进入下一个屏幕时,我在 myView.addGestureRecognizer(tapGesture) 处收到错误“致命错误:在隐式展开可选值时意外发现 nil”
【解决方案7】:

这里是ios Tapgesture; 首先你需要为 GestureRecognizer 创建动作,如下图所示在动作下编写以下代码

- (IBAction)tapgesture:(id)sender

{


[_password resignFirstResponder];


[_username resignFirstResponder];

NSLog(@" TapGestureRecognizer  tapped");

}

【讨论】:

    【解决方案8】:

    另一种方法是在视图中添加一个透明按钮

    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];
    

    然后,处理点击:

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

    【讨论】:

      【解决方案9】:

      斯威夫特 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
        }
      }
      

      使用

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

      【讨论】:

      • 谢谢。效果很好!
      • 喜欢这个!添加到所有项目;)
      【解决方案10】:

      创建一个手势识别器(子类),它将实现触摸事件,例如touchesBegan。之后您可以将其添加到视图中。

      这样您将使用组合而不是子类化(这是请求)。

      【讨论】:

        【解决方案11】:

        斯威夫特 3:

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

        【讨论】:

          【解决方案12】:

          你们为什么不试试SSEventListener

          您无需创建任何手势识别器并将您的逻辑分离到另一种方法。 SSEventListener 支持在视图上设置侦听器块以侦听单击手势、双击手势和 N-tap 手势(如果您愿意)以及长按手势。设置单击手势监听器变成了这样:

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

          【讨论】:

            【解决方案13】:

            Swift 4.2 和 Xcode 10

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

            如果你想使用 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)
                }
            } 
            

            我的 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...")
            }
            

            【讨论】:

              【解决方案14】:

              这些天看起来很简单。 这是 Swift 版本。

              let tap = UITapGestureRecognizer(target: self, action: #selector(viewTapped))
                  view.addGestureRecognizer(tap)
              
              @objc func viewTapped(recognizer: UIGestureRecognizer)
              {
                  //Do what you need to do!
              }
              

              【讨论】:

                【解决方案15】:

                目标-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 添加 touch 事件?

                它不要求 tap 事件。

                具体OP要实现UIControlEventTouchDown

                在这里将UIView 切换为UIControl 是正确的答案,因为Gesture Recognisers.touchDown.touchUpInside.touchUpOutside 等一无所知。

                此外,UIControl 继承自 UIView,因此您不会丢失任何功能。

                如果您只想轻点一下,那么您可以使用手势识别器。但是,如果您想要更精细的控制,就像这个问题所要求的那样,您将需要 UIControl。

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

                【讨论】:

                  【解决方案16】:

                  斯威夫特 5.3

                  闭包解决方案,基于: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
                      }
                  }
                  

                  使用:

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

                  【讨论】:

                    【解决方案17】:

                    简单

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

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2014-02-24
                      • 2011-05-07
                      • 1970-01-01
                      • 2021-02-09
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-05-03
                      相关资源
                      最近更新 更多