Zdarzenie z długim naciśnięciem przycisku UIButton

86

Chcę emulować długie naciśnięcie przycisku, jak mogę to zrobić? Myślę, że potrzebny jest minutnik. Rozumiem, UILongPressGestureRecognizerale jak mogę wykorzystać ten typ?

Andrea
źródło

Odpowiedzi:

160

Możesz zacząć od utworzenia i dołączenia UILongPressGestureRecognizerinstancji do przycisku.

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

Następnie zaimplementuj metodę obsługującą gest

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

To byłoby podstawowe podejście. Możesz również ustawić minimalny czas trwania prasy i jaki błąd jest tolerowany. Zauważ też, że metoda jest wywoływana kilka razy, jeśli po rozpoznaniu gestu, więc jeśli chcesz coś zrobić na końcu, będziesz musiał sprawdzić jej stan i obsłużyć.

Deepak Danduprolu
źródło
Wspaniały! dzięki! Przy okazji: if (gest.state == UIGestureRecognizerStateEnded) jest bardzo ważne, w przeciwnym razie dostaniesz wiele wydarzeń w swojej longPress void
RecycleRobot
29
Być może chcesz użyć if(gesture.state == UIGestureRecognizerStateBegan), ponieważ użytkownik oczekuje, że coś się stanie, gdy nadal naciskają (stan zaczął), a nie po zwolnieniu (zakończone).
shengbinmeng
28

Jako alternatywę dla zaakceptowanej odpowiedzi można to zrobić bardzo łatwo w Xcode przy użyciu Interface Builder.

Po prostu przeciągnij narzędzie rozpoznawania gestów z długim naciśnięciem z biblioteki obiektów i upuść je na przycisku w miejscu, w którym ma zostać wykonane długie naciśnięcie.

Następnie połącz akcję z właśnie dodanego narzędzia do rozpoznawania gestów z długim naciśnięciem do kontrolera widoku, wybierając nadawcę, który ma być typu UILongPressGestureRecognizer. W kodzie tegoIBAction użyj tego, który jest bardzo podobny do kodu sugerowanego w zaakceptowanej odpowiedzi:

W celu C :

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

Lub w Swift :

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

Muszę jednak przyznać, że po wypróbowaniu tego wolę sugestię @shengbinmeng jako komentarz do zaakceptowanej odpowiedzi, którą miałam użyć:

W celu C :

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

Lub w Swift :

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

Różnica polega na tym Ended, że po podniesieniu palca widać efekt długiego naciśnięcia. Z Beganefektem długiego naciśnięcia widać, gdy tylko długie naciśnięcie zostanie złapane przez system, jeszcze przed oderwaniem palca od ekranu.

alondono
źródło
18

Szybka wersja zaakceptowanej odpowiedzi

Wprowadziłem dodatkową modyfikację, używając UIGestureRecognizerState.Beganzamiast .Endedtego, ponieważ prawdopodobnie tego naturalnie spodziewałaby się większość użytkowników. Wypróbuj oba i przekonaj się sam.

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
źródło
9

Spróbuj tego:

Dodawanie przycisku viewDidLoad:jak poniżej

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

Teraz wywołaj metodę gestów w ten sposób

-(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
źródło
recognizer.view.tagdaje mi zły tag klikniętego przycisku UIButton. Jakieś rozwiązanie?
rohan-patel
3

Myślę, że potrzebujesz mojego rozwiązania.

powinieneś mieć ten kod dla pojedynczego naciśnięcia

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

najpierw dodaj gest długiego naciśnięcia do przycisku

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

następnie wielokrotnie wywołuj zdarzenie pojedynczego naciśnięcia, jeśli zostanie rozpoznany gest długiego naciśnięcia.

- (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
źródło
Nie należy dodawać zdarzenia w UIGestureRecognizertrakcie viewWillAppearcyklu życia, ponieważ za każdym razem, gdy pojawi się widok, zostanie dodany inny aparat do rozpoznawania gestów. Należy to zrobić w metodzie prywatnej wywoływanej podczas inicjalizacji.
Wikipedia
3

W przypadku Swift 4 należy zmienić „func longPress”, aby działał:

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
źródło
1

Odpowiedź w jednym wierszu, bez gestów:

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

Szczegóły: To wyzwala swój cel na trzech imprezach: 1- Natychmiast po palec dotyka przycisk: UIControlEventTouchDown. To wychwytuje początek długich naciśnięć. 2 & 3- Gdy użytkownik podniesie palec: UIControlEventTouchUpOutside& UIControlEventTouchUpInside. To oddaje koniec prasy użytkownika.

Uwaga: działa to dobrze, jeśli nie interesują Cię dodatkowe informacje dostarczane przez aparat rozpoznawania gestów (np. Lokalizacja dotyku itp.)

W razie potrzeby możesz dodać więcej wydarzeń pośrednich. Zobacz je wszystkie tutaj https://developer.apple.com/documentation/uikit/uicontrolevents?language=objc .

W Storyboard: Połącz swój przycisk z 3 wydarzeniami, a nie tylko domyślnym, które wybiera Storyboard (Touch Up Inside).

3 wydarzenia w scenorysie

CSawy
źródło
0

Mam podklasę UIButton dla mojej aplikacji, więc wyciągnąłem moją implementację. Możesz dodać to do swojej podklasy lub można to równie łatwo przekodować jako kategorię UIButton.

Moim celem było dodanie długiego naciśnięcia przycisku bez zaśmiecania kontrolerów widoku całym kodem. Zdecydowałem, że akcja powinna zostać wywołana, gdy rozpocznie się stan rozpoznawania gestów.

Pojawia się ostrzeżenie, którego nigdy nie próbowałem rozwiązać. Mówi, że to możliwy wyciek, myślałem, że przetestowałem kod i nie wycieka.

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

Aby przypisać akcję, dodaj tę linię do swojej metody viewDidLoad.

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

Akcję należy zdefiniować jak wszystkie IBActions (bez IBAction).

- (void)longPressAction:(id)sender {
    // sender is the button
}
Dan Loughney
źródło
0

Żaden pracował stąd Próbowałem pisania kodu longpress w IBActionprzycisk lub kliknięcie od storyboardw Controllerzamiast pisać wviewDidLoad

- (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
źródło