Subclassing UIPanGestureRecognizer to wait for Condition before recognition - objective-c

I'm trying to link two gestures one after another. UILongPressGestureRecognizer, then UIPanGestureRecognizer.
I want to detect the Long Press, then allow the Pan gesture to be recognized.
I've Subclassed UIPanGestureRecognizer and Added an panEnabled Bool iVar. In the initWith Frame I've set panEnabled to NO.
In Touches Moved I check to see if it is enabled, and then call Super touchesMoved if it is.
In my LongPress Gesture Handler, I loop though the View's Gestures till I find my Subclassed Gesture and then setPanEnabled to YES.
It seems like it is working, though its like the original pan gesture recognizer is not functioning properly and not setting the Proper states. I know if you Subclass the UIGestureRecognizer, you need to maintain the state yourself, but I would think that if you are subclassing UIPanGestureRecognizer, and for all the touches methods calling the super, that it would be setting the state in there.
Here is my subclass .h File
#import <UIKit/UIKit.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
#interface IoUISEListPanGestureRecognizer : UIPanGestureRecognizer {
int IoUISEdebug;
BOOL panEnabled;
}
- (id)initWithTarget:(id)target action:(SEL)action;
#property(nonatomic, assign) int IoUISEdebug;
#property(nonatomic, assign) BOOL panEnabled;
#end
here is the subclass .m File
#import "IoUISEListPanGestureRecognizer.h"
#implementation IoUISEListPanGestureRecognizer
#synthesize IoUISEdebug;
#synthesize panEnabled;
- (id)initWithTarget:(id)target action:(SEL)action {
[super initWithTarget:target action:action];
panEnabled = NO;
return self;
}
- (void)ignoreTouch:(UITouch*)touch forEvent:(UIEvent*)event {
[super ignoreTouch:touch forEvent:event];
}
-(void)reset {
[super reset];
panEnabled = NO;
}
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer {
return [super canPreventGestureRecognizer:preventedGestureRecognizer];
}
- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer{
return [super canBePreventedByGestureRecognizer:preventingGestureRecognizer];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
if (panEnabled) {
[super touchesMoved:touches withEvent:event];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesCancelled:touches withEvent:event];
}
#end

If you make a BOOL called canPan and include the following delegate methods you can have both a standard UILongPressGestureRecognizer and UIPanGestureRecognizer attached to the same view. On the selector that gets called when the long press gesture is recognized - change canPan to YES. You might want to disable the long press once it has been recognised and re-enable it when the pan finishes. - Don't forget to assign the delegate properties on the gesture recognisers.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if (!canPan && [gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
return NO;
}
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}

Related

Implementing UITapGestureRecognizer directly into UIView instead of ViewController does not work

As explained in this SO-answer I am trying to implement UITapGestureRecognizer in a subclass of UIIMageView. My approach can be found below.
An instance of MenuButtonImageView is a subview of homeScreenViewController.view.
I implemented touchesBegan:withEvent:, touchesMoved:withEvent: and touchesEnded:withEvent: too and do work fine.
Problem: Somehow handleSingleFingeredTap: is never called. What could be the problem with this?
#interface MenuButtonImageView : UIImageView
#property (nonatomic, weak) IBOutlet HomescreenViewController *homeScreenViewController;
#property (nonatomic, readwrite) Visibility visibility;
- (void)handleSingleFingeredTap:(UITapGestureRecognizer *)recognizer;
#end
#implementation MenuButtonImageView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.visibility = HIDDEN;
self.userInteractionEnabled = YES;
UITapGestureRecognizer * singleFingeredTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleFingeredTap:)];
singleFingeredTap.numberOfTapsRequired = 1;
[self addGestureRecognizer:singleFingeredTap];
}
return self;
}
- (void)handleSingleFingeredTap:(UITapGestureRecognizer *)recognizer {
NSLog(#"handleTap was called"); // This method is not called!
[self toggleMainMenu];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { ... }
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { ... }
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { ... }
#end
You add the recognizer in initWithFrame method. Check if your view is initialized this way. It may be created with another constructor like initWithCoder, and then your code is not executed. Put a breakpoint inside initWithFrame method to find out.
You can put the code in a separate method and call it from both constructors. It depends on how you use it. The initWithFrame is used quite common when you create a view from code.

TouchesMoved with UIButton xcode 4.4 iOS 5.1.1

I know this question seems to be already asked and answered but I can't resolve my issue.
I want to move the objects of my view to follow horizontal slides of a finger (going to previous or next page)
For this, I use TouchesBegan, TouchesMoved and TouchesEnded methods.
It works fine when the touches began on the view background but does not work when touches began on uibuttons.
To solve the problem, I have subclassed the uibuttons which i want to allow the gesture and it was working fine when i was on xCode 3.x and iOS 4.x
Today I just installed OSX Moutain Lion and started to work on xCode 4.4 and iOS 5.1.1 (iPAD).
And here I am with the very same app that worked fine and not working anymore.
Here is my UIButton subclass:
// myUIButton.h
#import <UIKit/UIKit.h>
#interface myUIButton : UIButton
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
#end
// myUIButton.m
#import "myUIButton.h"
#implementation myUIButton
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"uibutton touches began");
[self.nextResponder touchesBegan:touches withEvent:event];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"uibutton touches moved");
[self.nextResponder touchesMoved:touches withEvent:event];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"uibutton touches ended");
[self.nextResponder touchesEnded:touches withEvent:event];
}
#end
Here are the methods in my main class:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"view touches began");
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"view touches moved");
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"view touches ended");
}
When my touch began on an UIButton I get every NSLog from the subclass but the main touchesMoved is executed only once. (self.nextResponder seems to works only once)
Did something changed that make it not works on xcode 4.4 or iOS 5.1.1 ?
When I first tried to do that (on xcode 3.x and iOS 4.x) i found the solution here:
Is there a way to pass touches through on the iPhone?
But it not works anymore...
Could you help me?
Thanks a lot.
EDIT : The problem is the same using [super touches...] instead or in more of [self.nextResponder touches...]
I have solved the problem a while ago and does not remember how but there are differences in my files so I'll write here the new version that works.
// myUIButton.h
#import <Foundation/Foundation.h>
#interface myUIButton : UIButton {
}
#end
.
// myUIButton.m
#import "myUIButton.h"
#implementation myUIButton
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"uibutton touches began");
[super touchesBegan:touches withEvent:event];
[self.nextResponder touchesBegan:touches withEvent:event];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"uibutton touches moved");
[super touchesMoved:touches withEvent:event];
[self.nextResponder touchesMoved:touches withEvent:event];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"uibutton touches ended");
[super touchesEnded:touches withEvent:event];
[self.nextResponder touchesEnded:touches withEvent:event];
}
#end
In each view I need this behavior, I place a Pan Gesture Recognizer in the file.xib that I link to the action panRecognizer: defined in the file.m
// file.m
#synthesize slide_origin_x;
-(IBAction)panRecognizer:(UIPanGestureRecognizer *)recognizer {
// Recording movement
if (recognizer.state == UIGestureRecognizerStateBegan) {
self.slide_origin_x = [NSNumber numberWithFloat:recognizer.view.center.x];
}
// Choose an action
else if (recognizer.state == UIGestureRecognizerStateEnded) {
int to_launch_action = 100; // Action choosen after 100 pixels
int touch_move = [self.slide_origin_x intValue] - recognizer.view.center.x;
if (touch_move > (0 + to_launch_action)) {
/*
* What happens if the view slide to the left (eg : go_to_next)
*/
} else if (touch_move < (0 - to_launch_action)) {
/*
* What happens if the view slide to the right (eg : go_to_previous)
*/
}
// The view goes back to normal
recognizer.view.center = CGPointMake([self.slide_origin_x intValue], recognizer.view.center.y);
}
// The view is moved
else {
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y);
[recognizer setTranslation:CGPointMake(0,0) inView:self.view];
}
}
FYI : This works also on XCode5 and SDK6.1

UIView subclass doesn't respond to touches

I'm making an iPad project in which a class named "Car" (this is a separate file from the view controller) is supposed to be dragged around the main view.
I setup the class as I saw in an Apple example and I'm able to view my image when I run the application but it's like my class doesn't respond to my touches event and I can't solve the problem.
Here is my class code:
Car.h
#import <UIKit/UIKit.h>
#interface Car : UIView {
UIImageView *firstPieceView;
CGPoint startTouchPosition;
}
-(void)animateFirstTouchAtPoint:(CGPoint)touchPoint forView:(UIImageView *)theView;
-(void)animateView:(UIView *)theView toPosition:(CGPoint) thePosition;
-(void)dispatchFirstTouchAtPoint:(CGPoint)touchPoint forEvent:(UIEvent *)event;
-(void)dispatchTouchEvent:(UIView *)theView toPosition:(CGPoint)position;
-(void)dispatchTouchEndEvent:(UIView *)theView toPosition:(CGPoint)position;
#property (nonatomic, retain) IBOutlet UIImageView *firstPieceView;
#end
and this is my other class code: Car.m
#import "Car.h"
#implementation Car
#synthesize firstPieceView;
#define GROW_ANIMATION_DURATION_SECONDS 0.15 // Determines how fast a piece size grows when it is moved.
#define SHRINK_ANIMATION_DURATION_SECONDS 0.15 // Determines how fast a piece size shrinks when a piece stops moving.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Enumerate through all the touch objects.
NSUInteger touchCount = 0;
for (UITouch *touch in touches) {
// Send to the dispatch method, which will make sure the appropriate subview is acted upon
[self dispatchFirstTouchAtPoint:[touch locationInView:self] forEvent:nil];
touchCount++;
}
}
// Checks to see which view, or views, the point is in and then calls a method to perform the opening animation,
// which makes the piece slightly larger, as if it is being picked up by the user.
-(void)dispatchFirstTouchAtPoint:(CGPoint)touchPoint forEvent:(UIEvent *)event
{
if (CGRectContainsPoint([firstPieceView frame], touchPoint)) {
[self animateFirstTouchAtPoint:touchPoint forView:firstPieceView];
}
}
// Handles the continuation of a touch.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSUInteger touchCount = 0;
// Enumerates through all touch objects
for (UITouch *touch in touches) {
// Send to the dispatch method, which will make sure the appropriate subview is acted upon
[self dispatchTouchEvent:[touch view] toPosition:[touch locationInView:self]];
touchCount++;
}
}
// Checks to see which view, or views, the point is in and then sets the center of each moved view to the new postion.
// If views are directly on top of each other, they move together.
-(void)dispatchTouchEvent:(UIView *)theView toPosition:(CGPoint)position
{
// Check to see which view, or views, the point is in and then move to that position.
if (CGRectContainsPoint([firstPieceView frame], position)) {
firstPieceView.center = position;
}
}
// Handles the end of a touch event.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// Enumerates through all touch object
for (UITouch *touch in touches) {
// Sends to the dispatch method, which will make sure the appropriate subview is acted upon
[self dispatchTouchEndEvent:[touch view] toPosition:[touch locationInView:self]];
}
}
// Checks to see which view, or views, the point is in and then calls a method to perform the closing animation,
// which is to return the piece to its original size, as if it is being put down by the user.
-(void)dispatchTouchEndEvent:(UIView *)theView toPosition:(CGPoint)position
{
// Check to see which view, or views, the point is in and then animate to that position.
if (CGRectContainsPoint([firstPieceView frame], position)) {
[self animateView:firstPieceView toPosition: position];
}
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
// Enumerates through all touch object
for (UITouch *touch in touches) {
// Sends to the dispatch method, which will make sure the appropriate subview is acted upon
[self dispatchTouchEndEvent:[touch view] toPosition:[touch locationInView:self]];
}
}
#pragma mark -
#pragma mark === Animating subviews ===
#pragma mark
// Scales up a view slightly which makes the piece slightly larger, as if it is being picked up by the user.
-(void)animateFirstTouchAtPoint:(CGPoint)touchPoint forView:(UIImageView *)theView
{
// Pulse the view by scaling up, then move the view to under the finger.
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:GROW_ANIMATION_DURATION_SECONDS];
theView.transform = CGAffineTransformMakeScale(1.2, 1.2);
[UIView commitAnimations];
}
// Scales down the view and moves it to the new position.
-(void)animateView:(UIView *)theView toPosition:(CGPoint)thePosition
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:SHRINK_ANIMATION_DURATION_SECONDS];
// Set the center to the final postion
theView.center = thePosition;
// Set the transform back to the identity, thus undoing the previous scaling effect.
theView.transform = CGAffineTransformIdentity;
[UIView commitAnimations];
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UIImage *img = [ UIImage imageNamed: #"CyanSquare.png" ];
firstPieceView = [[UIImageView alloc] initWithImage: img];
//[img release];
[super addSubview:firstPieceView];
[firstPieceView release];
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
- (void)dealloc
{
[firstPieceView release];
[super dealloc];
}
#end
And here is my code for the view controller: (ParkingviewController.h)
#import <UIKit/UIKit.h>
#import "Car.h"
#interface ParkingViewController : UIViewController {
}
#end
and last but not least the ParkingViewController.m
#import "ParkingViewController.h"
#implementation ParkingViewController
- (void)dealloc
{
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
Car *car1 = [[Car alloc] init];
[self.view addSubview:car1];
[car1 release];
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
#end
Please forgive me if I've posted all the code but I want to be clear in every aspect of my project so that anyone can have the whole situation to be clear.
You need to set a frame for Car object that you are creating for touches to be processed. You are able to see the image as the clipsToBounds property of the view is set to NO by default.

How to subclass UITableView?

I honestly don't know how to subclass a UITableView. I'm super confused and looking for whatever help I can get. How do I go about "subclassing" a UITableView? Reason I need to do it is because I need for the table to respond to touches on the background so that keyboards can be hidden. I've tried googling but couldn't find anything. Any help is extremely appreciated!
Most of the time you shouldn't need to subclass UITableView, so see if you can avoid doing so first. If you absolutely have to, create a subclass that inherits from UITableView and override the touch-related methods in the implementation:
// MyTableView.h
#interface MyTableView : UITableView {
}
#end
// MyTableView.m
#implementation MyTableView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
[super touchesCancelled:touches withEvent:event];
}
#end
In your .h file declare it as a subclass:
#interface myViewController: UITableViewController
Then implement the UITableViewController delegate methods:
http://developer.apple.com/iphone/library/documentation/uikit/reference/UITableViewDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intf/UITableViewDelegate
To detect touches on a cell write your logic in the tableView:didSelectRowAtIndexPath: method: http://developer.apple.com/iphone/library/documentation/uikit/reference/UITableViewDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UITableViewDelegate/tableView:didSelectRowAtIndexPath:

Responding to touchesBegan in UIPickerView instead of UIView

I have a UIPickerView that gets faded out to 20% alpha when not in use. I want the user to be able to touch the picker and have it fade back in.
I can get it to work if I put a touchesBegan method on the main View, but this only works when the user touches the View. I tried sub-classing UIPickerView and having a touchesBegan in there, but it didn't work.
I'm guessing it's something to do with the Responder chain, but can't seem to work it out.
I've been searching for a solution to this problem for over a week. I'm answering you even if you're question is over a year old hoping this helps others.
Sorry if my language is not very technical, but I'm pretty new to Objective-C and iPhone development.
Subclassing UIpickerView is the right way to do it. But you've to override the - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event method. This is the method called whenever you touch the screen and it returns the view that will react to the touch. In other words the view whose touchesBegan:withEvent: method will be called.
The UIPickerView has 9 subviews! In the UIPickerView class implementation - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event won't return self (this means the touchesBegan:withEvent: you write in the subclass won't be called) but will return a subview, exactly the view at index 4 (an undocumented subclass called UIPickerTable).
The trick is to make the - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event method to return self so you have control over the touchesBegan:withEvent:, touchesMoved:withEvent: and touchesEnded:withEvent: methods.
In these methods, in order to keep the standard functionalities of the UIPickerView, you MUST remember to call them again but on the UIPickerTable subview.
I hope this makes sense. I can't write code now, as soon as I'm at home I will edit this answer and add some code.
Here is some code that does what you want:
#interface TouchDetectionView : UIPickerView {
}
- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event;
#end
#implementation TouchDetectionView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
[hitTestView touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
[hitTestView touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
[hitTestView touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
[hitTestView touchesCancelled:touches withEvent:event];
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
return self;
}
- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
UIView * hitTestView = [super hitTest:point withEvent:event];
return ( hitTestView == self ) ? nil : hitTestView;
}
Both of the above answers were very helpful, but I have a UIPickerView nested within a UIScrollView. I'm also doing continual rendering elsewhere on-screen while the GUI is present. The problem is that the UIPickerView doesn't update fully when: a non-selected row is tapped, the picker is moved so that two rows straddle the selection area, or a row is dragged but the finger slides outside of the UIPickerView. Then it's not until the UIScrollView is moved that the picker instantly updates. This result is ugly.
The problem's cause: my continual rendering was keeping the UIPickerView's animation from getting the CPU cycles it needed to finish, hence to show the correct, current selection. My solution --which works-- was this: in the UIPickerView's touchesEnded:withEvent:, execute something to pause my rendering for a short while. Here's the code:
#import "SubUIPickerView.h"
#implementation SubUIPickerView
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
[pickerTable touchesBegan:touches withEvent:event];
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
[pickerTable touchesMoved:touches withEvent:event];
}
- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
[singleton set_secondsPauseRendering:0.5f]; // <-- my code to pause rendering
[pickerTable touchesEnded:touches withEvent:event];
}
- (void) touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event
{
[pickerTable touchesCancelled:touches withEvent:event];
}
- (UIView*) hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
if (CGRectContainsPoint(self.bounds, point))
{
if (pickerTable == nil)
{
int nSubviews = self.subviews.count;
for (int i = 0; i < nSubviews; ++i)
{
UIView* view = (UIView*) [self.subviews objectAtIndex:i];
if ([view isKindOfClass:NSClassFromString(#"UIPickerTable")])
{
pickerTable = (UIPickerTable*) view;
break;
}
}
}
return self; // i.e., *WE* will respond to the hit and pass it to UIPickerTable, above.
}
return [super hitTest:point withEvent:event];
}
#end
and then the header, SubUIPickerView.h:
#class UIPickerTable;
#interface SubUIPickerView : UIPickerView
{
UIPickerTable* pickerTable;
}
#end
Like I said, this works. Rendering pauses for an additional 1/2 second (it already pauses when you slide the UIScrollView) allowing the UIPickerView animation to finish. Using NSClassFromString() means you're not using any undocumented APIs. Messing with the Responder chain was not necessary. Thanks to checcco and Tylerc230 for helping me come up with my own solution!
Set canCancelContentTouches and delaysContentTouches of parent view to NO, that worked for me
Couldn't find a recent, easier solution to this so I rigged something to solve my problem. Created an invisible button that stretches over the picker view. Connected that button with a "Touch Down" recognizer to my parent UIView. Now any functionality can be added, I happened to need a random selection timer to be invalidated when someone touches the picker view. Not elegant but it works.