【问题标题】:UIControl Subclass - Events called twiceUIControl 子类 - 事件被调用两次
【发布时间】:2011-10-05 02:47:42
【问题描述】:

我目前正在开发自定义 UIControl 子类。要跟踪触摸,我使用以下方法:

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
 NSLog(@"Start");
 CGPoint location = [touch locationInView:self];
 if ([self touchIsInside:location] == YES) {
    //Touch Down
    [self sendActionsForControlEvents:UIControlEventTouchDown];
    return YES;
 }
 else {
    return NO;
 }  
}

这按预期工作,@"Start" 只记录一次。下一步是使用 UIControlEventTouchDown 添加一个 Target 和一个 Selector。

[markItem addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];

这也有效,并且调用了 action: 方法。但这是我的问题。该动作被调用两次。我究竟做错了什么?我只使用一次[self sendActionsForControlEvents:UIControlEventTouchDown];,目标操作被调用了两次。我的代码有什么问题?

桑德罗·迈耶

【问题讨论】:

  • 两个调用中 TouchUpInside 事件的发送者是“self”吗?我不太确定 Cocoa Touch 中的视图层次结构,但您可能会同时收到“self”对象的 touch up 事件和 self 的子视图。
  • 是的。两次发送者都是我的 UIControl 子类的同一个对象。
  • 这个目标被调用两次的原因是系统自动发送UIControlEventTouchDown消息,并且在你的控制下你正在发送第二个消息。除此之外,您正在做的事情是完全合理的。如果您只想要UIControlEventTouchXXXXX 的自动触摸消息,则根本不需要beginTrackingWithTouch。但是,如果您通过触摸事件更改控件的外观,则需要这些功能。
  • 感谢 Robotbugs,解决了它!

标签: objective-c ios subclass uicontrol


【解决方案1】:

第一次调用 action 方法时,事件调度程序会在您调用后自动发生:

[markItem addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];

注册处理程序。

所以当你打电话时:

//Touch Down
[self sendActionsForControlEvents:UIControlEventTouchDown];

您正在生成对您的处理程序(以及任何其他已连接的)的第二次调用。

因此,您似乎不需要动作处理程序和 beginTracking - 使用其中一个。

更新:

鉴于您的评论和进一步思考:由于您是 UIControl 的子类,我认为您可能不想为自己注册事件处理程序。

您应该专门使用:

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
- (void)cancelTrackingWithEvent:(UIEvent *)event;   // event may be nil if cancelled for non-event reasons, e.g. removed from window

还有tracking 实例变量。

所以我认为您不应该发布事件或收听事件。此外,如果 beginTrackingWithTouch 事件不在您的视图中,是否真的有可能获得它?似乎不会。所以我认为你不需要测试来看看它是否在你的视野中。

因此,我认为可能值得退后一步,思考一下您正在尝试做什么并重新阅读 UIControl 文档。具体来说:

子类化注释 您可能想要扩展一个 UIControl 子类 两个原因之一:

观察或修改动作消息到目标的调度 特定事件为此,请覆盖sendAction:to:forEvent:, 评估传入的选择器、目标对象或UIControlEvents 位 掩码,然后按要求进行。

提供自定义跟踪行为(例如,更改 突出显示外观)为此,请覆盖以下一项或全部 方法:beginTrackingWithTouch:withEvent:, continueTrackingWithTouch:withEvent:, endTrackingWithTouch:withEvent:.

第一部分是让您的 UIControl 子类为您的控件的客户端或用户执行目标操作处理的非标准处理(这听起来不像您正在尝试做的事情,尽管您并没有真正做到给出一个高层次的描述)。

第二部分听起来更像您想要做的 - 在您的 UIControl 子类中自定义跟踪。

【讨论】:

  • 感谢您的回答。但我需要开始跟踪,以确定内部是否有触摸。所以你认为我只需要让自己 sendActionsForControlEvents: 离开?
  • 扩展了上面的答案,尝试再读一遍,看看是否有帮助。
  • 澄清我的问题。我将广告目标和选择器添加到 markItem 的行位于子类之外,而 markItem 是我的 UIControl 子类的对象。我会试试你说的。所以这 4 种跟踪方法应该处理消息的发送。
  • 谢谢你!我知道如何正确地对其进行子类化。跟踪方法会相应地发送动作!如果我使用 touchesBegan (等),我需要发送操作。但是跟踪方法为我做到了。如果我只是删除发送操作的行,我会按预期工作!谢谢!
【解决方案2】:

嗯.. 检查我的代码是否符合您的目标:

UIContr.h

@interface UIContr : UIControl {

}

@end

UIContr.m

#import "UIContr.h"
@implementation UIContr
- (id)initWithFrame:(CGRect)frame {

    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code.
    }
    return self;
}

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    NSLog(@"Start");
    CGPoint location = [touch locationInView:self];
    if (CGRectContainsPoint(self.frame, location)) {
        //Touch Down
        [self sendActionsForControlEvents:UIControlEventTouchDown];
        return YES;
    }
    else {
        return NO;
    }  
}

- (void)dealloc {
    [super dealloc];
}
@end

如何在 UIViewController 中使用:

- (void)viewDidLoad {
    UIContr *c = [[UIContr alloc] initWithFrame:CGRectMake(20, 20, 100, 100)];
    [c addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];
    c.backgroundColor = [UIColor redColor];
    [self.view addSubview:c];
}

-(void)action:(id)sender{
    NSLog(@"123");
}

【讨论】:

  • 一切正常。 “开始”和“123”只打印到控制台一次。尝试使用 UIControlEventTouchDown/UIControlEventTouchUpInside
  • 这很奇怪。我所有的代码看起来都像你的。只有您检查点是否在视图内的部分不同。我得到了两次调用的动作...... :-(
  • 它只被调用一次,因为您正在注册UIControlEventTouchUpInside,而不是您尝试从控件发送的UIControlEventTouchDown
  • 您不需要检查视图中的位置。重点始终在beginTrackingWithTouch 的视图中。
猜你喜欢
  • 2022-01-19
  • 2011-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-05
  • 1970-01-01
  • 2011-02-23
相关资源
最近更新 更多