如何检测UIImageView的触摸事件?

98

我已经将一个图片(UIImageView)放在了导航栏上。现在我想检测触摸事件并处理该事件。我该如何做?


在这种情况下,我会(并认为你应该)使用自定义的UIButton。 - titaniumdecoy
请检查 Swift 版本答案 https://dev59.com/NmQn5IYBdhLWcg3wETvj#41328885。 - Mohamed Jaleel Nazir
10个回答

138

实际上,不要那样做。

相反,添加一个自定义样式的按钮(除非您指定图像,否则不要使用按钮图形),覆盖在UIImageView上。然后将您想要调用的任何方法附加到该按钮上。

您可以使用该技术处理许多情况,您真正想要屏幕上的某个区域充当按钮而不是与Touch相关的操作。


我已经在导航栏上添加了一个按钮,并且也可以处理触摸事件。但是,我想在这个按钮上添加一个圆形图像。您能告诉我如何以编程方式实现吗?另外,您能告诉我如何以编程方式将按钮属性设置为“自定义”吗? - ebaccount
查看UIButton的文档 - 您需要为控件状态设置背景图像,您将需要不同的图像用于Normal vs. Selected/Highlighted。我相信按钮样式是您设置为UIButtonStyleCustom的 - 再次查看UIButton上的样式属性的文档。 - Kendall Helmstetter Gelner
1
在UIImageView上添加一个UIButton是不是有点过头了?你多加了一个对象,而你可以只实现已经存在的UIImageView对象的触摸方法。不是吗? - samvermette
33
如果你查看UIButton在内存中的大小,它实际上很小,每个屏幕只有几个。你可以免费获得整个目标动作绑定的不同状态(例如触摸抬起)和良好的行为,例如当你按下但是向侧面滑动时不会触发。基本上,按钮是整个系统中最精心制作的对象之一,认为自己将做出更好的自定义触摸代码是疯狂的。使用那些便宜且良好运作的东西,将自定义工作留给框架尚未处理的事情。 - Kendall Helmstetter Gelner
6
如果你只需要触摸事件,你还可以叠加一个UIControl(通过addTarget:action:forControlEvents:方法)。这比UIButton更节省一些资源,因为UIButton有图片和多个状态。此外,我使用预处理条件将叠加的控件背景颜色更改为粉色,以便我可以准确地看到它们的位置(并记住它们的存在 :-)。 - Jeff

115
一个UIImageView是从UIView继承而来的,后者又是从UIResponder继承而来的,因此它已经准备好处理触摸事件了。您需要提供touchesBegantouchesMovedtouchesEnded方法,如果用户点击图像,则这些方法将被调用。如果您只想要一个轻敲事件,那么使用带有图像设置为按钮图像的自定义按钮会更容易。但是,如果您想对轻击、移动等进行更精细的控制,那么这是正确的方法。
您还需要查看一些其他内容:
- 重写canBecomeFirstResponder并返回YES以指示该视图可以成为触摸事件的焦点(默认值为NO)。 - 将userInteractionEnabled属性设置为YES。对于UIViews,默认值为YES,但对于UIImageViews,默认值为NO,因此必须明确打开它。 - 如果您想响应多点触摸事件(即捏合、缩放等),则需要将multipleTouchEnabled设置为YES。

我尝试过了,但仍然无法接收到touchesBegan事件...为什么会这样? - Markus
5
@Markus: 我遇到了同样的问题,但是通过将父视图的userInteractionEnabled属性设置为YES来解决了它。请参考https://dev59.com/zW025IYBdhLWcg3wpHl_ - Saxon Druce

51

要为UIImageView添加触摸事件,请在您的.m文件中使用以下代码:

UITapGestureRecognizer *newTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(myTapMethod)];

[myImageView setUserInteractionEnabled:YES];

[myImageView addGestureRecognizer:newTap];


-(void)myTapMethod{
    // Treat image tap
}

userInteractionEnabled = true 是容易被忘记的部分,谢谢。 - Michael Peterson

23

您也可以添加UIGestureRecognizer。它不需要您在视图层次结构中添加其他元素,但仍提供了处理触摸事件的所有精美编写的代码,并具有相当简单的接口:

    UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc]
                                            initWithTarget:self action:@selector(handleSwipe:)];
    swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
    [imgView_ addGestureRecognizer:swipeRight];        
    [swipeRight release];
    UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc]
                                            initWithTarget:self action:@selector(handleSwipe:)];
    swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
    [imgView_ addGestureRecognizer:swipeLeft];
    [swipeLeft release];

10
不要忘记为imgView_设置UserInteractionEnabled属性。 - Anonymous White

13

我在过去的几个小时里参与了许多线程,试图找到解决我的问题的方法,但都没有成功。我发现许多开发人员都有这个问题,因此我认为这里的人会知道这个问题。我有多张图片放在一个UIScrollView中,尝试在它们上面获取点击事件。

我无法从一个UIImangeView获得任何事件,但是我确实可以从一个非常类似的带有非常相似参数的UILable中获取事件。在iOS 5.1下。

我已经完成了以下工作:

  1. 将`UIImageView`和父视图的`setUserInteractionEnabled`设置为YES。
  2. 将`UIImageView`的`setMultipleTouchEnabled`设置为YES。
  3. 尝试对`UIImageView`进行子类化,但没有任何帮助。

下面附上一些代码,在这段代码中,我初始化了一个UIImageViewUILabel,标签在触发事件方面运行正常。我尝试省略不相关的代码。

UIImageView *single_view = [[UIImageView alloc]initWithFrame:CGRectMake(200, 200, 100, 100)];
single_view.image = img;
single_view.layer.zPosition = 4;

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapGestureCaptured:)];
[single_view addGestureRecognizer:singleTap];
[single_view setMultipleTouchEnabled:YES];
[single_view setUserInteractionEnabled:YES];
[self.myScrollView addSubview:single_view];
self.myScrollView.userInteractionEnabled = YES;

UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
testLabel.backgroundColor = [UIColor redColor];
[self.myScrollView addSubview:testLabel];
[testLabel addGestureRecognizer:singleTap];
[testLabel setMultipleTouchEnabled:YES];
[testLabel setUserInteractionEnabled:YES];
testLabel.layer.zPosition = 4;

处理该事件的方法:

- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
    UIView *tappedView = [gesture.view hitTest:[gesture locationInView:gesture.view] withEvent:nil];
    NSLog(@"Touch event on view: %@", [tappedView class]);
}

就像之前所说的那样,接收到了标签点击事件。


6

不要创建一个可触摸的UIImageView并将其放置在导航栏上,而应该创建一个UIBarButtonItem,并将其制作成UIImageView。

首先制作图像视图:

UIImageView *yourImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"nameOfYourImage.png"]];

然后将您的图像视图制作为barbutton项:

UIBarButtonItem *yourBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:yourImageView];

然后将该条按钮项添加到您的导航栏中:
self.navigationItem.rightBarButtonItem = yourBarButtonItem;

记住,这段代码要放到一个导航控制器视图控制器数组中的视图控制器中。所以基本上,当这个视图控制器被展示时,这个“可点击的图片状栏按钮项”才会出现在导航栏中。当你推入另一个视图控制器时,这个导航栏按钮项将消失。

3

你可能需要覆盖包含UIImageView子视图的UIView(或其子类)的touchesBegan:withEvent:方法。

在此方法中,测试任何UITouch触摸是否落在UIImageView实例(假设它被称为imageView)的边界内。

也就是说,[touch locationInView]元素的CGPoint元素是否与[imageView bounds]元素的CGRect元素相交?请查看函数CGRectContainsPoint以运行此测试。


谢谢您的回复。我已经像这样添加了视图: [navBar addSubview:self.pImage]; // 作为导航栏的子视图添加。我已经重写了函数,但是该函数从未被调用。我已将UIImageView的属性userInteractionEnabled设置为YES。我有什么遗漏吗? - ebaccount
请查看touchesBegan:withEvent:方法。搜索引擎上有很多关于它的工作原理的示例。 - Alex Reynolds

1
首先,您应该放置一个UIButton,然后您可以为此按钮添加背景图像,或者您需要在按钮上方放置一个UIImageView。
或:
您可以将点击手势添加到UIImageView中,这样当点击UIImageView时就会获得点击操作。

0

对于那些寻找Swift 4解决方案的人,您可以使用以下方法来检测UIImageView上的触摸事件。

let gestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageViewTapped))
imageView.addGestureRecognizer(gestureRecognizer)
imageView.isUserInteractionEnabled = true

然后,您需要按照以下方式定义您的选择器:

@objc func imageViewTapped() {
    // Image has been tapped
}

-2
在该视图上添加手势。将图像添加到该视图中,然后它也会检测图像上的手势。您可以尝试使用触摸事件的委托方法。在这种情况下,它也可能被检测到。

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