忽略透明UIControl上的触摸 - 不由添加的操作函数处理

时间:2014-10-30 03:58:03

标签: ios cocoa-touch uiview hittest uicontrol

我有一个自定义UIControl,其中包含一些其他控件。在这些控件之间有空白空间,我UIControl的背景需要透明。

我需要捕获在我的自定义UIControl上发生的所有触摸事件,即使它们恰好位于其他控件之间(透明区域)。我不能使用手势识别器,我需要更多的控制然后他们提供。相反,我想注册这样的触摸处理函数:

myControl.addTarget(self, action: "handleTouchDown:event:", forControlEvents: UIControlEvents.TouchDown)

通过这种方法,我会收到myControl非透明区域发生的触摸,但不会发生透明背景的那些区域。

我尝试在自定义控件中覆盖hitTest::point:withEvent,不检查alpha值。但是当透明控制区域发生触摸时,甚至不会调用hitTest::point:withEvent。我用自定义layer替换了我的控件的CALayer,并且在那里也覆盖了hitTest而没有结果(层上似乎没有调用hitTest)。


更多细节(编辑)

要提供完美答案(并赢得赏金),您需要做的就是:

  1. 创建简单应用,添加一个UIControl(例如UIButton)。
  2. UIControl中移除所有内容(来自UIButton的文字)并使其背景透明(设置为清除颜色或将Alpha通道设置为0)。
  3. 使用addTarget::action:forControlEvents:方法在控件上注册UIControlEvents.TouchDown个事件。在处理程序方法中打印一些东西到控制台。
  4. 运行应用程序,按下控件。什么都没有打印到控制台。让它工作 - 不要使用手势识别器我需要addTarget::action:forControlEvents:提供的粒度。没有黑客解决方案。我知道将控件上的背景alpha通道设置为0.01会让它突然工作,但这是我不想要的黑客攻击。在这里描述一下你做了什么。

3 个答案:

答案 0 :(得分:2)

关注编辑部分:

https://github.com/soxjke/TransparentControl

1)如果我将背景颜色设置为+[UIColor clearColor],那么触摸效果会非常好。所以你不需要做更多的事情,继续使用清晰的颜色。 (顶部按钮)
2)如果我设置alpha = 0,则不处理触摸。 OK(中键)
3)为了处理这个问题,有一个简单的解决方案(底部按钮),子类UIButton(实际上你可以使用层次结构中的任何内容到UIView)。覆盖hitTest:withEvent:

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    return CGRectContainsPoint(self.bounds, point) ? self : nil;
}

PROFIT
4)如果你需要更深入,请使用

touchesBegan:withEvent:
touchesMoved:withEvent:
touchesEnded:withEvent:
touchesCancelled:withEvent:

Rob Glassey

中提出的UIResponder子类{p} {p}}

P.S。我将结束主题。不知道你的任务究竟是什么,但是告诉你不能使用识别器,因为你需要对所有触摸事件“更多控制”,发现你不知道手势识别器的可能性。所以,根据我的经验,我会说你宁愿发明自行车然后做好解决方案。

P.P.S。如果我和其他人在这里建议方法对你不起作用 - 请检查你的控件userInteractionEnabled

附录(查看要测试的控制器代码:):

#import "ViewController.h"
#import "TransparentControl.h"

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UIButton *buttonClearColor;
@property (weak, nonatomic) IBOutlet UIButton *buttonAlpha0;
@property (weak, nonatomic) IBOutlet TransparentControl *customButtonAlpha0;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.buttonClearColor addTarget:self action:@selector(touchUpInside:) forControlEvents:UIControlEventTouchUpInside];
    [self.buttonClearColor addTarget:self action:@selector(touchUpOutside:) forControlEvents:UIControlEventTouchUpOutside];
    [self.buttonClearColor addTarget:self action:@selector(touchDown:) forControlEvents:UIControlEventTouchDown];

    [self.buttonAlpha0 addTarget:self action:@selector(touchUpInside:) forControlEvents:UIControlEventTouchUpInside];
    [self.buttonAlpha0 addTarget:self action:@selector(touchUpOutside:) forControlEvents:UIControlEventTouchUpOutside];
    [self.buttonAlpha0 addTarget:self action:@selector(touchDown:) forControlEvents:UIControlEventTouchDown];

    [self.customButtonAlpha0 addTarget:self action:@selector(touchUpInside:) forControlEvents:UIControlEventTouchUpInside];
    [self.customButtonAlpha0 addTarget:self action:@selector(touchUpOutside:) forControlEvents:UIControlEventTouchUpOutside];
    [self.customButtonAlpha0 addTarget:self action:@selector(touchDown:) forControlEvents:UIControlEventTouchDown];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

- (void)touchUpInside:(id)sender
{
    NSLog(@"%s", __PRETTY_FUNCTION__);
}

- (void)touchDown:(id)sender
{
    NSLog(@"%s", __PRETTY_FUNCTION__);
}

- (void)touchUpOutside:(id)sender
{
    NSLog(@"%s", __PRETTY_FUNCTION__);
}

@end

答案 1 :(得分:1)

hitTest的文档提到完全透明的内容被忽略,因此覆盖hitTest本身可能不足以解决这个问题,因为任何调用hitTest都没有调用当物体是透明的时候。

相反,如果您需要访问原始触摸事件(无论是什么)(UIResponder和{{继承),我建议您尝试使用较低级UIView触摸方法。 1}}所以你可以使用。)

他们是:

UIControl

第一个参数是touchesBegan:withEvent: touchesMoved:withEvent: touchesEnded:withEvent: touchesCancelled:withEvent: 个触摸,第二个参数NSSet就像你在其他方法中所指的那样......

使用此功能,您无需添加目标操作,但会在自定义控件上覆盖这些方法。这些是较低级别(和极端的老式学校),但应该让您完全控制触摸事件。

答案 2 :(得分:1)

我使用空UIControl方法对drawRect进行了子类化,但它确实有效。

根据文档,opaque和其他一些控件会忽略UIButton,因此无法将其用作此技术的控制点。但奇怪的是,视图的默认背景颜色是透明的(无)。

通过继承UIControl并设置opaque = NO,您可以创建一个drawRect方法,该方法不会完全填充框架并允许"透明"没有设置alpha = 0的区域允许hitTest:withEvent:仍然接收事件。由于该元素是UIView,因此您应该能够添加视图,然后实现自己的drawRect调用所有子视图'等效函数,而不是绘制应该是透明的区域。

我的基本ViewController元素,ImageView是为了确保它有效。

@implementation MyViewController
- (void)viewDidLoad {
    [ super viewDidLoad ];

    transparentControl = [ [ TransparentControl alloc ] initWithFrame:CGRectMake( 0, 0, 400, 400 ) ];
    [ transparentControl addTarget:self action:@selector(printText) forControlEvents:UIControlEventTouchUpInside];

    // Create an image view below the button for proof the control is transparent
    UIImageView * imageView = [ [ UIImageView alloc ] initWithImage:[ UIImage imageNamed:@"BGImage.jpg" ] ];
    imageView.frame = self.view.frame;

    [ self.view addSubview:imageView ];
    [ self.view addSubview:transparentControl ];
}

 -( void )printText {
    NSLog( @"Hello, this is a transparent button." );
}
@end

我的透明控制。

@implementation TransparentControl

- ( instancetype )initWithFrame:( CGRect )frame {
    if( self = [ super initWithFrame:frame ] ) {
        self.opaque = NO;
        self.userInteractionEnabled = YES;
    }
    return self;
}

- ( void )drawRect:(CGRect)rect {
}
@end