Skip to content

Instantly share code, notes, and snippets.

@jbenet
Created August 8, 2010 09:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jbenet/513796 to your computer and use it in GitHub Desktop.
Save jbenet/513796 to your computer and use it in GitHub Desktop.
UIControl Category to capture and save UIControlEvents flag to its own tag
// The MIT License
//
// Copyright (c) 2010 Juan Batiz-Benet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//------------------------------------------------------------------------------
// UIControl+CaptureUIControlEvents Category
// Author: Juan Batiz-Benet
// github gist at: http://gist.github.com/513796
// PROBLEM: upon firing, UIControlEvents are not passed into the target action
// assigned to the particular event. This would be useful in order to have only
// one action that switches based on the UIControlEvent fired.
//
// SOLUTION: add a way to store the UIControlEvent triggered in the UIEvent.
//
// PROBLEM: But we cannot override private APIs, so:
// (Worse) solution: have the UIControl store the UIControlEvent last fired.
//
// The UIControl documentation states that:
// > When a user touches the control in a way that corresponds to one or more
// > specified events, UIControl sends itself sendActionsForControlEvents:.
// > This results in UIControl sending the action to UIApplication in a
// > sendAction:to:from:forEvent: message.
//
// One would think that sendActionsForControlEvents: can be overridden (or
// subclassed) to store the flag, but it is not so. It seems that
// sendActionsForControlEvents: is mainly there for clients to trigger events
// programatically.
//
// Instead, I had to set up a scheme that registers an action for each control
// event that one wants to track. I decided not to track all the events (or in
// all UIControls) for performance and ease of use.
//
// Example Usage:
// // (on setup)
// UIControlEvents capture = UIControlEventTouchDown;
// capture |= UIControlEventTouchDown;
// capture |= UIControlEventTouchUpInside;
// capture |= UIControlEventTouchUpOutside;
// [myControl captureEvents:capture];
// [myControl addTarget:self action:@selector(touch:) forControlEvents:capture];
//
// ...
// // the target action
// - (void) touch:(UIControl *)sender {
// UIColor *color = [UIColor clearColor];
// switch (sender.tag) {
// case UIControlEventTouchDown: color = [UIColor redColor]; break;
// case UIControlEventTouchUpInside: color = [UIColor blueColor]; break;
// case UIControlEventTouchUpOutside: color = [UIColor redColor]; break;
// }
// sender.backgroundColor = color;
// }
//------------------------------------------------------------------------------
@interface UIControl (CaptureUIControlEvents)
- (void) captureEvents:(UIControlEvents)controlEvents;
@end
// The MIT License
//
// Copyright (c) 2010 Juan Batiz-Benet (jbenet@cs.stanford.edu)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Hmmm one method for each UIControlEvent... so gross. I can hear the purist
// inside me screaming: ``You're doing it wrong!''
@implementation UIControl (CaptureUIControlEvents)
- (void) captureUIControlEventTouchDown {
self.tag = UIControlEventTouchDown;
}
- (void) captureUIControlEventTouchDownRepeat {
self.tag = UIControlEventTouchDownRepeat;
}
- (void) captureUIControlEventTouchDragInside {
self.tag = UIControlEventTouchDragInside;
}
- (void) captureUIControlEventTouchDragOutside {
self.tag = UIControlEventTouchDragOutside;
}
- (void) captureUIControlEventTouchDragEnter {
self.tag = UIControlEventTouchDragEnter;
}
- (void) captureUIControlEventTouchDragExit {
self.tag = UIControlEventTouchDragExit;
}
- (void) captureUIControlEventTouchUpInside {
self.tag = UIControlEventTouchUpInside;
}
- (void) captureUIControlEventTouchUpOutside {
self.tag = UIControlEventTouchUpOutside;
}
- (void) captureUIControlEventTouchCancel {
self.tag = UIControlEventTouchCancel;
}
- (void) captureUIControlEventValueChanged {
self.tag = UIControlEventValueChanged;
}
- (void) captureUIControlEventEditingDidBegin {
self.tag = UIControlEventEditingDidBegin;
}
- (void) captureUIControlEventEditingChanged {
self.tag = UIControlEventEditingChanged;
}
- (void) captureUIControlEventEditingDidEnd {
self.tag = UIControlEventEditingDidEnd;
}
- (void) captureUIControlEventEditingDidEndOnExit {
self.tag = UIControlEventEditingDidEndOnExit;
}
- (SEL) captureActionForUIControlEvent:(UIControlEvents)controlEvent
{
switch (controlEvent) {
case UIControlEventTouchDown:
return @selector(captureUIControlEventTouchDown);
case UIControlEventTouchDownRepeat:
return @selector(captureUIControlEventTouchDownRepeat);
case UIControlEventTouchDragInside:
return @selector(captureUIControlEventTouchDragInside);
case UIControlEventTouchDragOutside:
return @selector(captureUIControlEventTouchDragOutside);
case UIControlEventTouchDragEnter:
return @selector(captureUIControlEventTouchDragEnter);
case UIControlEventTouchDragExit:
return @selector(captureUIControlEventTouchDragExit);
case UIControlEventTouchUpInside:
return @selector(captureUIControlEventTouchUpInside);
case UIControlEventTouchUpOutside:
return @selector(captureUIControlEventTouchUpOutside);
case UIControlEventTouchCancel:
return @selector(captureUIControlEventTouchCancel);
case UIControlEventValueChanged:
return @selector(captureUIControlEventValueChanged);
case UIControlEventEditingDidBegin:
return @selector(captureUIControlEventEditingDidBegin);
case UIControlEventEditingChanged:
return @selector(captureUIControlEventEditingChanged);
case UIControlEventEditingDidEnd:
return @selector(captureUIControlEventEditingDidEnd);
case UIControlEventEditingDidEndOnExit:
return @selector(captureUIControlEventEditingDidEndOnExit);
}
return nil; // shouldnt get here.
}
- (void) considerCapturing:(UIControlEvents)event
forControlEvents:(UIControlEvents)controlEvents
{
SEL captureAction = [self captureActionForUIControlEvent:event];
if (captureAction != nil && controlEvents & event)
[self addTarget:self action:captureAction forControlEvents:event];
}
- (void) captureEvents:(UIControlEvents)events {
for (UIControlEvents event = 0x01; event; event <<= 1)
[self considerCapturing:event forControlEvents:events];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment