2009-08-15 97 views
6

说我有这样的代码:如何制作超级视图拦截按钮触摸事件?

#import <UIKit/UIKit.h> 

@interface MyView : UIView 
@end 
@implementation MyView 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    // How can I get this to show up even when the button is touched? 
    NSLog(@"%@", [touches anyObject]); 
} 

@end 

@interface TestViewAppDelegate : NSObject <UIApplicationDelegate> 
{ 
    UIWindow *window; 
} 

@end 

@implementation TestViewAppDelegate 

- (void)applicationDidFinishLaunching:(UIApplication *)application 
{ 
    window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 

    MyView *view = [[MyView alloc] initWithFrame:[window frame]]; 
    [view setBackgroundColor:[UIColor whiteColor]]; 

    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 
    [button setTitle:@"Hiya!" forState:UIControlStateNormal]; 
    [button setFrame:CGRectMake(100.0, 100.0, 200.0, 200.0)]; 
    [view addSubview:button]; 

    [window addSubview:view]; 
    [window makeKeyAndVisible]; 
} 


- (void)dealloc 
{ 
    [window release]; 
    [super dealloc]; 
} 

@end 

有没有办法拦截越来越发送到该按钮的触摸事件?我最终想要做的是制作一个UIView子类,当它检测到滑动时会告诉它的视图控制器(或委托,无论哪个),以便将下一个视图控制器“推送”到堆栈上(类似于iPhone主屏幕)。我想这是第一步,但如果我不正确地处理这些问题,我会接受建议。

回答

1

感谢您的建议和丰富的答复。我结束了使用this页面上显示的解释:(在“技巧1:模拟照片应用程序刷/缩放/使用单个UIScrollView滚动”)。

16

我很希望看到其他的解决方案,但我知道最简单的方法之一就是覆盖以下两种方法的UIView:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; 
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event; 

这些方法被调用,以确定是否触摸距离视图或其任何子视图的边界,因此这是拦截触摸然后传递它的好点。只要做任何你想要的东西,然后

return [super hitTest:point withEvent:event]; 

return [super pointInside:point withEvent:event]; 
+0

你不是指返回[superview hitTest:point withEvent:event]; – 2012-02-14 15:06:19

+0

'super'是对的,因为你想调用类的父类方法,'superview'会跳过这个。 – keegan3d 2012-10-04 01:16:50

0

我相信你将不得不继承的UIButton在这种情况下,并覆盖到UIResponder的触摸和动作事件的响应。然后,您可以将它们转发给您想要假定UIButton子类可以访问的任何对象。

在这种情况下,您会将它们传递给UIButton的超级视图。

@interface MyButton : UIButton 
@end 

@implementation MyButton 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [[self superview] touchesMoved:touches withEvent:event]; 
} 

@end 

UIResponder documentation

+1

不幸的是,UIButton是一个类集群。这意味着子类化几乎是不可能的。 – 2009-08-19 22:56:14

+0

我不知道这是不好的。他确实提到了一些UIView子类,所以我只是在UIButton中使用它,因为他在他的示例代码中使用了它。 – criscokid 2009-08-20 04:25:50

4

本能会说:“子类UIButton的”,但UIButton的实际上是一类集群(即对象的实际类型透明的变化取决于你想要做什么样的按钮),这使得子类化非常困难。在重写UIButton的时候,在这种方法上你可以做的不多。

当我需要解决一个几乎相同的问题时,我想出了一个视图,它使用组合来显示代理UIView,但仍允许进行触摸拦截。下面是它如何工作的:

@interface MyView : UIView { 
    UIView * visibleView; 
} 

- (id) initWithFrame:(CGRect)frame controlClass:(Class)class; 

@end 


@implementation MyView 

- (id) initWithFrame:(CGRect)frame controlClass:(Class)class { 
    if (self = [super initWithFrame:frame]) { 
    CGRect visibleViewFrame = frame; 
    visibleViewFrame.origin = CGPointZero; 
    visibleView = [[class alloc] initWithFrame:visibleViewFrame]; 
    [visibleView setUserInteractionEnabled:NO]; 
    [self addSubview:visibleView]; 

    [self setUserInteractionEnabled:YES]; 
    [self setBackgroundColor:[UIColor clearColor]]; 
    } 
    return self; 
} 

- (void) dealloc { 
    [visibleView removeFromSuperview]; 
    [visibleView release], visibleView = nil; 
    [super dealloc]; 
} 

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    if (someCondition == YES) { 
    [visibleView touchesBegan:touches withEvent:event]; 
    } 
} 

//and similar methods for touchesMoved:, touchesEnded:, etc 

@end 

的基本思想,这就是你要嵌入按钮(或其他)到一个容器类(类似于你在你的问题中描述的)。但是,您正在禁用按钮上的交互,这意味着当用户点击按钮时,点击事件将“落入”按钮并进入包含超级视图的按钮(在此为您的MyView实例)。从那里,你可以适当地处理触摸。如果你想让按钮“响应”触摸,只需通过发送适当的UIResponder消息来允许按钮。 (您可能需要在visibleView重新启用userInteractionEnabled第一,虽然,我不能确定这一点。)

正如我上文所述,我已经使用这个方法(不是这个确切的实现,但这种模式)相当成功,当我需要在界面上有一个按钮时,还要捕获UITouch对象本身。

3

可能我建议使用这种方法来代替:

UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] 
               initWithTarget:self 
               action:@selector(tapDetected:)]; 
    tapRecognizer.numberOfTapsRequired = 1; 
    tapRecognizer.numberOfTouchesRequired = 1; 

    [self.view addGestureRecognizer:tapRecognizer]; 

您可以从上海华做到这一点,没有必要进行自定义UI元素。

+0

不错,UITapGestureRecognizer与包含多个UILabel的UIView一起工作得很好。 – joelsand 2012-09-11 19:24:25