Como adicionar um evento de toque a um UIView?

280

Como adiciono um evento de toque a um UIView?
Eu tento:

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

Não quero criar uma subclasse e substituir

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
Manni
fonte
Para rápido você pode obtê-lo aqui: stackoverflow.com/questions/28675209/...
Mr.Javed Multani

Respostas:

578

No iOS 3.2 e superior, você pode usar os reconhecedores de gestos. Por exemplo, é assim que você lida com um evento de toque:

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

Há um monte de gestos embutidos também. Confira os documentos para manipulação de eventos do iOS e UIGestureRecognizer. Eu também tenho um monte de código de exemplo no github que pode ajudar.

Nathan Eror
fonte
Mas isso é sobrescrever a ação padrão da exibição. ¿É possível chamar a ação de toque padrão da visualização? Algo como [super touchesBegan]? ... #
M Penades
2
O que a linha CGPoint faz?
Zakdances
2
@yourfriendzak the CGPointrepresenta a localização da torneira na super visão da vista tocada. Você pode usar este ponto para mover a vista tocada (ou uma visão de irmão) para o local tocado. Isso é mais útil no manipulador UIPanGestureRecognizerpara arrastar a exibição pela tela.
EAN Nathan Eror #
5
ótima resposta concisa, obrigado. mas sheesh, não seria legal se isso fosse um pouquinho mais fácil ?! :)
natbro
Não é tão ruim, mas eu gostaria que houvesse uma API baseada em bloco como github.com/neror/ftutils/blob/master/Headers/FTUtils/… . O Xcode 4 também oferece suporte para adicionar / configurar reconhecedores de gestos no Interface Builder.
Nathan Eror 24/05
126

Reconhecedores de gestos

Há vários eventos de toque comum (ou gestos) dos quais você pode ser notificado quando adiciona um Reconhecimento de gestos à sua exibição. Os seguintes tipos de gesto são suportados por padrão:

  • UITapGestureRecognizer Toque em (toque brevemente na tela uma ou mais vezes)
  • UILongPressGestureRecognizer Toque longo (tocando na tela por um longo tempo)
  • UIPanGestureRecognizer Pan (movendo o dedo pela tela)
  • UISwipeGestureRecognizer Deslize (movendo o dedo rapidamente)
  • UIPinchGestureRecognizer Aperte (movendo dois dedos juntos ou separados - geralmente para aumentar o zoom)
  • UIRotationGestureRecognizer Girar (movendo dois dedos em uma direção circular)

Além desses, você também pode criar seu próprio reconhecedor de gestos personalizado.

Adicionando um gesto no Interface Builder

Arraste um reconhecedor de gestos da biblioteca de objetos para a sua exibição.

insira a descrição da imagem aqui

Arraste o controle do gesto no Esboço do documento para o código do View Controller para criar uma saída e uma ação.

insira a descrição da imagem aqui

Isso deve ser definido por padrão, mas também verifique se a Ação do Usuário Ativada está definida como true para sua visualização.

insira a descrição da imagem aqui

Adicionando um gesto programaticamente

Para adicionar um gesto programaticamente, você (1) cria um reconhecedor de gestos, (2) o adiciona a uma visualização e (3) cria um método chamado quando o gesto é reconhecido.

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

Notas

  • O senderparâmetro é opcional. Se você não precisar de uma referência ao gesto, pode deixar de fora. Se você fizer isso, remova o(sender:) nome do método após a ação.
  • A nomeação do handleTapmétodo foi arbitrária. Nomeie como quiser .action: #selector(someMethodName(sender:))

Mais exemplos

Você pode estudar os reconhecedores de gestos que adicionei a essas visualizações para ver como eles funcionam.

insira a descrição da imagem aqui

Aqui está o código para esse projeto:

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

Notas

  • Você pode adicionar vários reconhecedores de gestos a uma única exibição. Por uma questão de simplicidade, no entanto, eu não fiz isso (exceto pelo gesto de furto). Se você precisar para o seu projeto, leia a documentação do reconhecedor de gestos . É bastante compreensível e útil.
  • Problemas conhecidos dos meus exemplos acima: (1) A visualização panorâmica redefine seu quadro no próximo evento de gesto. (2) A exibição de furto vem da direção errada no primeiro furto. (Esses erros nos meus exemplos não devem afetar sua compreensão de como funcionam os reconhecedores de gestos.)
Suragch
fonte
2
Sua resposta é realmente agradável e útil com descrição detalhada. E é por isso que tenho voto que você responde também. Mas você perdeu uma instrução que acho que deve incluir na sua resposta, como a explicou em detalhes. Essa instrução é sobre como definir "<yourView> .EnableUserInteraction = TRUE". Espero que você concorde comigo.
Er. Vihar
3
A fim de fazer este trabalho em um UIViewé preciso também acrescentar:self.isUserInteractionEnabled = true;
Neiker
52

Eu acho que você pode simplesmente usar

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

Quero dizer headerView se estende de UIControl.

LiCheng
fonte
7
Essa é a melhor resposta. UITapGestureRecognizernão é uma substituição de UIControlEventTouchDown. A Tapgeralmente compõe UIControlEventTouchDowne UIControlEventTouchUpInside.
ohho
62
A UIViewnão é a UIControle, portanto, não tem acesso addTarget:action:forControlEvents:.
RobertJoseph
9
Observe também que um UIControl herda do UIView. Para meus propósitos, tudo o que eu precisava fazer era uma simples troca de tipo de subclasse.
Pretzels1337
1
você pode definir sua classe como UIControl @RobertJoseph. Vá para o arquivo xib e defina a classe View Custom como UIControl. agora você pode lidar com eventos nele ..
Zar E Ahmer
2
Então, por que essa é uma solução melhor novamente, pois estou mudando a herança apenas para lidar com torneiras?
Anthony Glyadchenko
21

Swift 3 e Swift 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
  }
}

Usar

yourView.addTapGesture(tapNumber: 1, target: self, action: #selector(yourMethod))
Indrajit Sinh Rayjada
fonte
Obrigado. Funciona bem!
Mikrasya
1
Amo isso! Adicionando a todos os projetos;)
budidino 28/06
17

Com base na resposta aceita, você pode definir uma macro:

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

Essa macro usa o ARC, então não há release chamada.

Exemplo de uso de macro:

handle_tap(userpic, self, @selector(onTapUserpic:));
Rudyryk
fonte
4
Se você criar a exibição no storyboard, não se esqueça de ativar a opção "interação com o usuário ativada".
david
onde devemos definir macros em .h ou .m e qual deve ser o nome dos parâmetros. i significativo #define handle_tap (UIView vista, delegado delegado, o selector SEL) fazer ..
Zar E Ahmer
8

Você pode conseguir isso adicionando o Gesture Recogniser no seu código.

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

Etapa 2: ViewController.m:

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

NOTA: aqui o seuView no meu caso foi @property (strong, nonatomic) IBOutlet UIView *localView;

EDIT: * localView é a caixa branca no Main.storyboard a partir de baixo

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Annu
fonte
Estou tendo várias visualizações para que eu possa o ID do remetente?
Moin Shirazi
Você precisa ir para a subvisão interna e, em seguida, pode paas o remetente. [Classe UIButton]]) {// Vá para essa visualização específica // Aqui você chegou até esse ponto. }}
Annu
8

No Swift 4.2 e no Xcode 10

Use UITapGestureRecognizer para adicionar evento de toque

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

Se você deseja usar o 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)
    }
} 

Eu tenho três visualizações no meu ViewController chamado view1, view2 e 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...")
}
iOS
fonte
6

Aqui está uma versão 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
    }
}
Esqarrouth
fonte
o que é BlockTap?
He Yifei #
1
Oh cara, esqueci essa parte. É uma função personalizada. Aqui: github.com/goktugyil/EZSwiftExtensions/blob/master/Sources/…
Esqarrouth
5

Swift 3:

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

func handleTapGestureRecognizer(_ gestureRecognizer: UITapGestureRecognizer) {

}
Giang
fonte
1

Parece bastante simples nos dias de hoje. Esta é a versão Swift.

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

@objc func viewTapped(recognizer: UIGestureRecognizer)
{
    //Do what you need to do!
}
daj mi spokój
fonte
0

Aqui está o iOS tapgesture; Primeiro, você precisa criar uma ação para o GestureRecognizer depois de escrever o código abaixo na ação, como mostrado abaixo

- (IBAction)tapgesture:(id)sender

{


[_password resignFirstResponder];


[_username resignFirstResponder];

NSLog(@" TapGestureRecognizer  tapped");

}
sathish
fonte
0

Outra maneira é adicionar um botão transparente à visualização

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

E então, manipule o clique:

- (void)buttonClicked:(id)sender
{}
thanhbinh84
fonte
0

Crie um reconhecedor de gestos (subclasse) que implementará eventos de toque, como touchesBegan. Você pode adicioná-lo à exibição depois disso.

Dessa forma, você usará a composição em vez de subclassificar (que foi a solicitação).

Geri Borbás
fonte
0

Por que vocês não experimentam o SSEventListener ?

Você não precisa criar nenhum reconhecedor de gestos e separar sua lógica para outro método. SSEventListenersuporta a configuração de blocos de ouvinte em uma exibição para ouvir gestos de toque único, gesto de toque duplo e gesto de toque N, se desejar, e pressione e segure. A configuração de um único ouvinte de gesto de toque se torna assim:

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

Shengsheng
fonte
0

Objetivo-C:

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

Rápido:

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

A pergunta pergunta:

Como adiciono um evento de toque a um UIView?

Não está solicitando um evento de toque .

Especificamente, o OP quer implementar UIControlEventTouchDown

Mudar o UIViewque UIControlé a resposta certa aqui porque Gesture Recognisersnão sei nada sobre .touchDown, .touchUpInside,.touchUpOutside etc.

Além disso, o UIControl herda do UIView, para que você não perca nenhuma funcionalidade.

Se tudo o que você deseja é um toque, é possível usar o Reconhecedor de gestos. Mas se você deseja um controle mais preciso, como esta pergunta pede, precisará do UIControl.

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

janakmshah
fonte