Événement UIButton Long Press

86

Je veux émuler une longue pression sur un bouton, comment puis-je faire cela? Je pense qu'une minuterie est nécessaire. Je vois UILongPressGestureRecognizermais comment puis-je utiliser ce type?

Andrea
la source

Réponses:

160

Vous pouvez commencer par créer et attacher l' UILongPressGestureRecognizerinstance au bouton.

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

Et puis implémentez la méthode qui gère le geste

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

Maintenant, ce serait l'approche de base. Vous pouvez également définir la durée minimale de la presse et le degré d'erreur tolérable. Et notez également que la méthode est appelée quelques fois si vous après avoir reconnu le geste donc si vous voulez faire quelque chose à la fin de celui-ci, vous devrez vérifier son état et le gérer.

Deepak Danduprolu
la source
Super! Merci! Btw: le if (gesture.state == UIGestureRecognizerStateEnded) est très important, sinon vous aurez beaucoup d'événements dans votre longPress void
RecycleRobot
29
Vous voudrez peut-être utiliser if(gesture.state == UIGestureRecognizerStateBegan), car l'utilisateur s'attend à ce que quelque chose se produise lorsqu'il appuie toujours sur (l'état a commencé), pas lorsqu'il relâche (terminé).
shengbinmeng
28

Comme alternative à la réponse acceptée, cela peut être fait très facilement dans Xcode en utilisant Interface Builder.

Faites simplement glisser un outil de reconnaissance de gestes à appui long depuis la bibliothèque d'objets et déposez-le au-dessus du bouton à l'endroit où vous souhaitez effectuer une action de pression longue.

Ensuite, connectez une action de la reconnaissance de gestes à appui long qui vient d'être ajouté à votre contrôleur de vue, en sélectionnant l'expéditeur à être de type UILongPressGestureRecognizer. Dans le code de cela, IBActionutilisez ceci, qui est très similaire au code suggéré dans la réponse acceptée:

En Objective-C :

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

Ou dans Swift :

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

Mais je dois admettre qu'après l'avoir essayé, je préfère la suggestion faite par @shengbinmeng comme commentaire à la réponse acceptée, qui était d'utiliser:

En Objective-C :

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

Ou dans Swift :

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

La différence est qu'avec Ended, vous voyez l'effet de la pression longue lorsque vous soulevez votre doigt. Avec Began, vous voyez l'effet de la pression longue dès que la pression longue est captée par le système, avant même de lever le doigt de l'écran.

alondono
la source
18

Version rapide de la réponse acceptée

J'ai apporté la modification supplémentaire de l'utilisation UIGestureRecognizerState.Beganplutôt que .Endedpuisque c'est probablement ce à quoi la plupart des utilisateurs s'attendent naturellement. Essayez les deux et voyez par vous-même.

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
la source
9

Essaye ça:

Ajout d'un bouton viewDidLoad:comme ci-dessous

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

Maintenant, appelez la méthode gestuelle comme ceci

-(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
la source
recognizer.view.tagme donne une mauvaise balise de UIButton cliqué. Toute solution?
rohan-patel
3

Je pense que tu as besoin de ma solution.

vous devriez avoir ce code pour une seule pression

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

tout d'abord, ajoutez un geste de pression longue sur le bouton

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

puis appelez à plusieurs reprises l'événement de pression unique si un geste de pression longue est reconnu.

- (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
la source
Vous ne devez pas ajouter l' événement UIGestureRecognizerpendant le viewWillAppearcycle de vie, car chaque fois que la vue apparaît, un autre outil de reconnaissance de gestes sera ajouté. Cela devrait être fait dans une méthode privée appelée lors de l'initialisation.
WikipediaBrown
3

Pour Swift 4, le "func longPress" doit être modifié pour le faire fonctionner:

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
la source
1

Réponse en une ligne, sans gestes:

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

Détails: Cela déclenche votre cible sur trois événements: 1- Immédiatement une fois doigt touche la touche: UIControlEventTouchDown. Cela capture de longues pressions de démarrage. 2 & 3- Lorsque l'utilisateur lève le doigt: UIControlEventTouchUpOutside& UIControlEventTouchUpInside. Cela capture la fin de la presse utilisateur.

Remarque: cela fonctionne bien si vous ne vous souciez pas des informations supplémentaires fournies par le module de reconnaissance de gestes (par exemple, l'emplacement du toucher, etc.)

Vous pouvez ajouter d'autres événements intermédiaires si nécessaire, voir tous ici https://developer.apple.com/documentation/uikit/uicontrolevents?language=objc .

Dans Storyboard: connectez votre bouton aux 3 événements, pas seulement à celui par défaut sélectionné par Storyboard (Retouche à l'intérieur).

3 événements dans le storyboard

CSawy
la source
0

J'ai un UIButton sous-classé pour mon application, j'ai donc retiré mon implémentation. Vous pouvez l'ajouter à votre sous-classe ou cela pourrait tout aussi bien être recodé qu'une catégorie UIButton.

Mon objectif était d'ajouter une pression longue sur mon bouton sans encombrer mes contrôleurs de vue avec tout le code. J'ai décidé que l'action devrait être appelée lorsque l'état de reconnaissance de mouvement commence.

Il y a un avertissement que je n'ai jamais pris la peine de résoudre. Dit que c'est une fuite possible, je pense que j'ai testé le code et qu'il ne fuit pas.

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

Pour affecter l'action, ajoutez cette ligne à votre méthode viewDidLoad.

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

L'action doit être définie comme toutes les IBActions (sans IBAction).

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

Aucun n'a fonctionné, j'ai donc essayé d'écrire du code longpress IBActionou de cliquer sur un bouton storyboardau Controllerlieu d'écrire dansviewDidLoad

- (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
la source