Evento UIButton Long Press

86

Quero emular um botão de pressionamento longo, como posso fazer isso? Acho que é necessário um cronômetro. Entendo, UILongPressGestureRecognizermas como posso utilizar esse tipo?

Andrea
fonte

Respostas:

160

Você pode começar criando e anexando a UILongPressGestureRecognizerinstância ao botão.

UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
[self.button addGestureRecognizer:longPress];
[longPress release];

E então implemente o método que lida com o gesto

- (void)longPress:(UILongPressGestureRecognizer*)gesture {
    if ( gesture.state == UIGestureRecognizerStateEnded ) {
         NSLog(@"Long Press");
    }
}

Agora, esta seria a abordagem básica. Você também pode definir a duração mínima da impressão e quanto erro é tolerável. E também note que o método é chamado poucas vezes se você depois de reconhecer o gesto, então se você quiser fazer algo no final dele, você terá que verificar seu estado e manipulá-lo.

Deepak Danduprolu
fonte
Super! obrigado! A propósito: o if (gesture.state == UIGestureRecognizerStateEnded) é muito importante, caso contrário, você obterá muitos eventos no seu vazio
longPress
29
Talvez você queira usar if(gesture.state == UIGestureRecognizerStateBegan), porque o usuário espera que algo aconteça quando ainda está pressionando (o estado Começou), não quando ele soltou (Terminado).
shengbinmeng
28

Como alternativa à resposta aceita, isso pode ser feito facilmente no Xcode usando o Interface Builder.

Basta arrastar um Reconhecedor de gestos de pressionamento longo da Biblioteca de objetos e soltá-lo no topo do botão onde deseja pressionar prolongadamente.

Em seguida, conecte uma ação do Long Press Gesture Recognizer recém-adicionado ao controlador de exibição, selecionando o remetente para ser do tipo UILongPressGestureRecognizer. No código desse IBActionuso, que é muito semelhante ao código sugerido na resposta aceita:

Em Objective-C :

if ( sender.state == UIGestureRecognizerStateEnded ) {
     // Do your stuff here
}

Ou em Swift :

if sender.state == .Ended {
    // Do your stuff here
}

Mas devo admitir que depois de tentar, prefiro a sugestão feita por @shengbinmeng como comentário à resposta aceita, que era usar:

Em Objective-C :

if ( sender.state == UIGestureRecognizerStateBegan ) {
     // Do your stuff here
}

Ou em Swift :

if sender.state == .Began {
    // Do your stuff here
}

A diferença é que com Ended, você vê o efeito do toque longo ao levantar o dedo. Com Began, você vê o efeito do toque longo assim que o toque longo for capturado pelo sistema, mesmo antes de tirar o dedo da tela.

Alondono
fonte
18

Versão rápida da resposta aceita

Fiz a modificação adicional de usar em UIGestureRecognizerState.Beganvez de, .Endeduma vez que é provavelmente o que a maioria dos usuários naturalmente espera. Experimente os dois e veja por si mesmo.

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // add gesture recognizer
        let longPress = UILongPressGestureRecognizer(target: self, action: #selector(longPress(_:)))
        self.button.addGestureRecognizer(longPress)
        
    }

    func longPress(gesture: UILongPressGestureRecognizer) {
        if gesture.state == UIGestureRecognizerState.began {
            print("Long Press")
        }
    }
    
    @IBAction func normalButtonTap(sender: UIButton) {
        print("Button tapped")
    }
}
Suragch
fonte
8

Experimente isto:

Adicionando botão viewDidLoad:como abaixo

-(void)viewDidLoad {
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [btn setTag:1]; //you can set any integer value as tag number
    btn.title = @"Press Me";
    [btn setFrame:CGRectMake(50.0, 50.0, 60.0, 60.0)];

    // now create a long press gesture
    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPressTap:)];
    [btn addGestureRecognizer:longPress];
}

Agora chame o método de gesto assim

-(void)longPressTap:(id)sender {
     UIGestureRecognizer *recognizer = (UIGestureRecognizer*) sender
    // Recogniser have all property of button on which you have clicked
    // Now you can compare button's tag with recogniser's view.tag  
    // View frame for getting the info on which button the click event happened 
    // Then compare tag like this
    if(recognizer.view.tag == 1) { 
       // Put your button's click code here
    }

    // And you can also compare the frame of your button with recogniser's view
    CGRect btnRect = CGRectMake(50.0, 50.0, 60.0, 60.0);
    if(recogniser.view.frame == btnRect) {
       //put your button's click code here
    }

   // Remember frame comparing is alternative method you don't need  to write frame comparing code if you are matching the tag number of button 
}
TheTiger
fonte
recognizer.view.tagme dá a tag errada do UIButton clicado. Qualquer solução?
rohan-patel de
3

Eu acho que você precisa da minha solução.

você deve ter este código para um único toque

- (IBAction)buttonDidPress:(id)sender {
    NSLog("buttonDidPress");
}

primeiro, adicione um gesto de toque longo para o botão

- (void)viewWillAppear:(BOOL)animated
{
    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(buttonDidLongPress:)];
    [self.button addGestureRecognizer:longPress];
}

em seguida, chame o evento de toque único repetidamente se o gesto de toque longo for reconhecido.

- (void)buttonDidLongPress:(UILongPressGestureRecognizer*)gesture
{
    switch (gesture.state) {
        case UIGestureRecognizerStateBegan:
        {
            self.timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(buttonDidPress:) userInfo:nil repeats:YES];

            NSRunLoop * theRunLoop = [NSRunLoop currentRunLoop];
            [theRunLoop addTimer:self.timer forMode:NSDefaultRunLoopMode];
        }
            break;
        case UIGestureRecognizerStateEnded:
        {
            [self.timer invalidate];
            self.timer = nil;
        }
            break;
        default:
            break;
    }
}
Jerry Juang
fonte
Você não deve adicionar o UIGestureRecognizerdurante o viewWillAppearevento de ciclo de vida, porque sempre que a visualização aparecer, outro reconhecedor de gesto será adicionado. Isso deve ser feito em um método privado que é chamado durante a inicialização.
WikipediaBrown
3

Para Swift 4, o "func longPress" precisa ser alterado para que funcione:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        // add guesture recognizer
        let longPress = UILongPressGestureRecognizer(target: self, action: #selector(longPress(_:)))
        self.button.addGestureRecognizer(longPress)

    }

   @objc func longPress(_ guesture: UILongPressGestureRecognizer) {
        if guesture.state == UIGestureRecognizerState.began {
            print("Long Press")
        }
    }

    @IBAction func normalButtonTap(sender: UIButton) {
        print("Button tapped")
    }
}
Bevan
fonte
1

Resposta de uma linha, sem gestos:

[btn addTarget:self action:@selector(handleTouch:) forControlEvents:UIControlEventTouchDown | UIControlEventTouchUpInside | UIControlEventTouchUpOutside];

Detalhes: Isso desencadeia o seu alvo em três eventos: 1- Imediatamente, uma vez toques de dedo pressionado o botão: UIControlEventTouchDown. Isso captura o início de pressionamentos longos. 2 e 3- Quando o usuário levanta o dedo: UIControlEventTouchUpOutside& UIControlEventTouchUpInside. Isso captura o final da imprensa do usuário.

Observação: isso funciona bem se você não se importar com as informações extras fornecidas pelo reconhecedor de gestos (por exemplo, localização do toque, etc.)

Você pode adicionar mais eventos intermediários se necessário, veja todos aqui https://developer.apple.com/documentation/uikit/uicontrolevents?language=objc .

No Storyboard: Conecte seu botão aos 3 eventos, não apenas ao padrão que o Storyboard seleciona (Touch Up Inside).

3 eventos em storyboard

CSawy
fonte
0

Eu tenho um UIButton subclasse para meu aplicativo, então retirei minha implementação. Você pode adicionar isso à sua subclasse ou pode ser facilmente recodificado como uma categoria UIButton.

Meu objetivo era adicionar o toque longo ao meu botão sem sobrecarregar meus controladores de visualização com todo o código. Decidi que a ação deve ser chamada quando o estado do reconhecedor de gestos começa.

Há um aviso que nunca me preocupei em resolver. Diz que é um possível vazamento, pensei ter testado o código e não vaza.

@interface MYLongButton ()
@property (nonatomic, strong) UILongPressGestureRecognizer *gestureRecognizer;
@property (nonatomic, strong) id gestureRecognizerTarget;
@property (nonatomic, assign) SEL gestureRecognizerSelector;
@end

@implementation MYLongButton

- (void)addLongPressTarget:(CGFloat)interval target:(id)target action:(SEL)selector
{
    _gestureRecognizerTarget = target;
    _gestureRecognizerSelector = selector;
    _gestureRecognizer = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(handleLongPressGestureRecognizer:)];
    _gestureRecognizer.minimumPressDuration = interval;

    [self addGestureRecognizer:_gestureRecognizer];
}

- (void)handleLongPressGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
        NSAssert([_gestureRecognizerTarget respondsToSelector:_gestureRecognizerSelector], @"target does not respond to selector");

        self.highlighted = NO;

        // warning on possible leak -- can anybody fix it?
        [_gestureRecognizerTarget performSelector:_gestureRecognizerSelector withObject:self];
    }
}

Para atribuir a ação, adicione esta linha ao seu método viewDidLoad.

[_myLongButton addLongPressTarget:0.75 target:self selector:@selector(longPressAction:)];

A ação deve ser definida como todas as IBActions (sem a IBAction).

- (void)longPressAction:(id)sender {
    // sender is the button
}
Dan Loughney
fonte
0

Nenhum funcionou, portanto, tentei escrever código longpress em IBActionou clicar storyboardno botão em em Controllervez de escrever emviewDidLoad

- (IBAction)btnClick:(id)sender {

    tag = (int)((UIButton *)sender).tag;

// Long press here instead of in viewDidLoad

    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
    longPress.cancelsTouchesInView = NO;
    [sender addGestureRecognizer:longPress];

}
karan
fonte