UIButton长按事件

89

我想模拟长按按钮,该怎么做?我认为需要一个计时器。

我看到了UILongPressGestureRecognizer,但我该如何使用这种类型?

9个回答

161
你可以通过创建并附加UILongPressGestureRecognizer实例到按钮来开始操作。
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
[self.button addGestureRecognizer:longPress];
[longPress release];

然后实现处理该手势的方法

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

现在这将是基本的方法。您也可以设置按压的最短持续时间以及允许的误差量。并且请注意,如果您想要在识别手势后执行某些操作,则该方法将被调用几次,因此您需要检查它的状态并处理它。


超棒!谢谢! 顺便说一下,if ( gesture.state == UIGestureRecognizerStateEnded ) 这个条件非常重要,否则你会在你的 longPress void 中得到很多事件。 - RecycleRobot
32
你或许想要使用 if(gesture.state == UIGestureRecognizerStateBegan),因为用户希望在他们仍在按住屏幕时(即状态为 Began)就能看到某些反应,而不是在他们松开手指时(即 Ended)。 - shengbinmeng

29

除了被接受的答案,这个问题也可以在Xcode中使用Interface Builder轻松解决。

只需从对象库中拖动一个长按手势识别器(Long Press Gesture Recognizer),并将其放到您想要添加长按操作的按钮上即可。

然后,从刚刚添加的长按手势识别器(Long Press Gesture Recognizer)连接一个操作(Action)到您的视图控制器,选择发送方类型为UILongPressGestureRecognizer。 在那个IBAction的代码中使用以下内容,这非常类似于被接受的答案中提供的代码:

Objective-C中:

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

或者用Swift

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

但是我不得不承认,在尝试后,我更喜欢@shengbinmeng在被接受的答案下面作为评论提出的建议,即使用:

在Objective-C中:

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

或者用Swift:

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

不同的是,使用 Ended 时,您会在手指离开屏幕后看到长按的效果。而使用 Began 时,即使在您还没有将手指离开屏幕之前,系统捕获到了长按的动作,您也能看到长按的效果。


20

接受答案的 Swift 版本

我做了额外的修改,使用UIGestureRecognizerState.Began而不是.Ended,因为这可能是大多数用户自然期望的。尝试两种方式并自行查看。

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

我们应该在 func longPress 前面加上 @objc 吗? - grep

10

尝试这样做:

viewDidLoad:中添加以下代码来添加按钮:

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

现在这样调用手势方法。
-(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 
}

recognizer.view.tag 给出了错误的被点击 UIButton 的标签。有任何解决方案吗? - rohan-patel

5
我认为你需要我的解决方案。
对于单击,您应该使用以下代码。
- (IBAction)buttonDidPress:(id)sender {
    NSLog("buttonDidPress");
}

首先,将长按手势添加到按钮中。

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

如果检测到长按手势,则重复调用单击事件。
- (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;
    }
}

不应该在 viewWillAppear 生命周期事件期间添加 UIGestureRecognizer,因为每当视图出现时,都会添加另一个手势识别器。这应该在初始化期间调用的私有方法中完成。 - WikipediaBrown

5
对于 Swift 4,"func longPress" 需要进行更改才能正常工作:
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")
    }
}

做到了,仍然适用于Swift 5.7.1和Xcode 14.1。这段代码可以在按钮长按时更改UIImageView的图像,并在释放按钮时恢复为先前的图像。https://github.com/timsonner/ios-uikit-ui-controls - Tim Sonner

1

一行回答,没有手势:

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

详情: 这会在三个事件中触发您的目标: 1- 当手指触摸按钮时立即触发:UIControlEventTouchDown。这会捕获长按开始。 2和3- 当用户抬起手指时触发:UIControlEventTouchUpOutsideUIControlEventTouchUpInside。这会捕获用户按下结束。

注意:如果您不关心手势识别器提供的额外信息(例如触摸位置等),则此方法效果很好。

如果需要,您可以添加更多中间事件,请在此处查看所有事件 https://developer.apple.com/documentation/uikit/uicontrolevents?language=objc

在Storyboard中: 将您的按钮连接到3个事件,而不仅仅是Storyboard选择的默认事件(Touch Up Inside)。

3 events in storyboard


似乎在Swift中不起作用。出现错误:“二元运算符 '|' 不能应用于两个 'UIControl.Event' 操作数”。 - alc77

0

由于没有一个方法起作用,因此我尝试在Controller中的IBAction或按钮单击事件以及storyboard中编写长按代码,而不是在viewDidLoad中编写。

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

}

0
我在我的应用中有一个子类化的UIButton,所以我已经拿出了我的实现。您可以将其添加到您的子类中,或者这同样容易地被重写为UIButton类别。
我的目标是在不使我的视图控制器代码混乱的情况下向我的按钮添加长按功能。我决定当手势识别器状态开始时调用该操作。
有一个警告出现,我从未想过解决它。说它可能会泄漏,但我测试了代码并没有泄漏。
@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];
    }
}

在你的viewDidLoad方法中添加以下代码来分配这个动作。
[_myLongButton addLongPressTarget:0.75 target:self selector:@selector(longPressAction:)];

这个动作应该像所有的IBAction一样被定义(不需要使用IBAction关键字)。

- (void)longPressAction:(id)sender {
    // sender is the button
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接