问题
I'm currently working on a custom UIControl Subclass. To track the touches I use the following Method:
- (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;
}
}
This works as expected and @"Start" is loged exactely once. The next step is that I add a Target and a Selector with UIControlEventTouchDown.
[markItem addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];
This works also and the action: method is called. But that's my problem. The action is called twice. What am I doing wrong? I just use [self sendActionsForControlEvents:UIControlEventTouchDown]; once and the target action is called twice. What's wrong with my code?
Sandro Meier
回答1:
The first call to the action method happens automatically by the event dispatcher once you've called:
[markItem addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];
to register the handler.
So when you then call:
//Touch Down
[self sendActionsForControlEvents:UIControlEventTouchDown];
you are generating the second call to your handler (and any others that are hooked up).
So it seems like you don't need both the action handler and the beginTracking - use one or the other.
Update:
Given your comment and further thought: since you are a subclass of UIControl, I think you probably don't want to be registering for event handlers for yourself.
Instead you should exclusively use:
- (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
Also the tracking instance variable.
So I think you should not be posting events or listening to events. Further, is it actually possible to get a beginTrackingWithTouch event if it's not in your view? Doesn't seem like it would be. So I don't think you need the testing to see if it's in your view.
So I think it might be worth stepping back and thinking about what you are trying to do and re-reading UIControl documentation. Specifically:
Subclassing Notes You may want to extend a UIControl subclass for either of two reasons:
To observe or modify the dispatch of action messages to targets for particular events To do this, override
sendAction:to:forEvent:, evaluate the passed-in selector, target object, orUIControlEventsbit mask, and proceed as required.To provide custom tracking behavior (for example, to change the highlight appearance) To do this, override one or all of the following methods:
beginTrackingWithTouch:withEvent:,continueTrackingWithTouch:withEvent:,endTrackingWithTouch:withEvent:.
The first part is for having your UIControl subclass do non-standard handling of target action processing for clients or users of your control (that doesn't sound like what you are trying to do, though you didn't really give a high-level description).
The second part sounds more like what you are wanting to do - custom tracking within your UIControl subclass.
回答2:
Hm.. Check my code for your aims:
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
How to use in 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");
}
来源:https://stackoverflow.com/questions/6689893/uicontrol-subclass-events-called-twice