Evento de pulsación larga de UIButton

86

Quiero emular un botón de presión larga, ¿cómo puedo hacer esto? Creo que se necesita un temporizador. Ya veo, UILongPressGestureRecognizerpero ¿cómo puedo utilizar este tipo?

Andrea
fuente

Respuestas:

160

Puede comenzar creando y adjuntando la UILongPressGestureRecognizerinstancia al botón.

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

Y luego implementa el método que maneja el gesto

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

Ahora bien, este sería el enfoque básico. También puede establecer la duración mínima de la prensa y cuánto error es tolerable. Y también tenga en cuenta que el método se llama pocas veces si después de reconocer el gesto, por lo que si desea hacer algo al final, tendrá que verificar su estado y manejarlo.

Deepak Danduprolu
fuente
¡Súper! ¡Gracias! Por cierto: el if (gesto.state == UIGestureRecognizerStateEnded) es muy importante, de lo contrario, obtendrá muchos eventos en su void
longPress
29
Quizás quieras usarlo if(gesture.state == UIGestureRecognizerStateBegan), porque el usuario espera que suceda algo cuando todavía están presionando (el estado Comenzó), no cuando sueltan (Terminado).
shengbinmeng
28

Como alternativa a la respuesta aceptada, esto se puede hacer muy fácilmente en Xcode usando Interface Builder.

Simplemente arrastre un Reconocimiento de gestos de pulsación larga desde la Biblioteca de objetos y suéltelo en la parte superior del botón donde desee la acción de pulsación larga.

A continuación, conecte una acción del Reconocimiento de gestos de pulsación larga que acaba de agregar a su controlador de vista, seleccionando el remitente para que sea del tipo UILongPressGestureRecognizer. En el código de ese IBActionuse esto, que es muy similar al código sugerido en la respuesta aceptada:

En Objective-C :

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

O en Swift :

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

Pero debo admitir que después de probarlo, prefiero la sugerencia hecha por @shengbinmeng como comentario a la respuesta aceptada, que era usar:

En Objective-C :

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

O en Swift :

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

La diferencia es que con Ended, ves el efecto de la pulsación larga cuando levantas el dedo. Con Began, verá el efecto de la pulsación larga tan pronto como el sistema capte la pulsación larga, incluso antes de levantar el dedo de la pantalla.

alondono
fuente
18

Versión rápida de la respuesta aceptada

Hice la modificación adicional de usar en UIGestureRecognizerState.Beganlugar de, .Endedya que eso es probablemente lo que la mayoría de los usuarios esperarían naturalmente. Pruébalos ambos y compruébalo por ti mismo.

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
fuente
8

Prueba esto:

Añadiendo un botón viewDidLoad:como a continuación

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

Ahora llama al método de gestos así

-(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
fuente
recognizer.view.tagme da una etiqueta incorrecta de UIButton hecho clic. ¿Alguna solución?
rohan-patel
3

Creo que necesitas mi solución.

debe tener este código para una sola pulsación

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

primero, agregue un gesto de presión larga al botón

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

luego, llame al evento de pulsación única repetidamente si se reconoce el gesto de pulsación larga.

- (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
fuente
No debe agregar el evento UIGestureRecognizerdurante el viewWillAppearciclo de vida porque cada vez que aparece la vista, se agregará otro reconocedor de gestos. Esto debe hacerse en un método privado que se llama durante la inicialización.
WikipediaBrown
3

Para Swift 4, es necesario cambiar "func longPress" 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
fuente
1

Respuesta de una línea, sin gestos:

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

Detalles: Esta active su objetivo en tres eventos: 1- Inmediatamente una vez que toques dedo hacia abajo el botón: UIControlEventTouchDown. Esto captura el inicio de pulsaciones largas. 2 y 3- Cuando el usuario levanta el dedo: UIControlEventTouchUpOutside& UIControlEventTouchUpInside. Esto captura el final de la prensa del usuario.

Nota: esto funciona bien si no le importa la información adicional proporcionada por el reconocedor de gestos (por ejemplo, la ubicación del toque, etc.)

Puede agregar más eventos intermedios si es necesario, verlos todos aquí https://developer.apple.com/documentation/uikit/uicontrolevents?language=objc .

En Storyboard: conecte su botón a los 3 eventos, no solo al predeterminado que Storyboard selecciona (Touch Up Inside).

3 eventos en storyboard

CSawy
fuente
0

Tengo un UIButton subclasificado para mi aplicación, así que he sacado mi implementación. Puede agregar esto a su subclase o esto podría recodificarse fácilmente como una categoría UIButton.

Mi objetivo era agregar la pulsación larga a mi botón sin saturar mis controladores de vista con todo el código. Decidí que la acción debería llamarse cuando comience el estado del reconocedor de gestos.

Hay una advertencia que sale y que nunca me he molestado en resolver. Dice que es una posible fuga, creo que he probado el código y no se filtra.

@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 asignar la acción, agregue esta línea a su método viewDidLoad.

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

La acción debe definirse como todas las IBActions (sin la IBAction).

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

Ninguno funcionó, por lo tanto, intenté escribir código de pulsación larga IBActiono hacer clic storyboarden el botón desde adentro en Controllerlugar de escribir enviewDidLoad

- (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
fuente