Collision detection (CGRectIntersectRect) - ios

I have two images: first image size is 50x85 and second image size is 50x113. When I touch the screen image goes up and second image is shown and when I release the screen image goes down and first image is shown. Now the problem is when I'm touching the screen collision happens earlier than when I'm not touching the screen.
How could I make that in second image about 30px at bottom won't collide, but image will still be there?
Edit: Here is some of the code:
-(void)AstronautMove
{
[self Collision];
Astronaut.center = CGPointMake(Astronaut.center.x, Astronaut.center.y + Y);
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
Y = -10;
x.image = [UIImage imageNamed:#"y.png"];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
Y = 17;
x.image = [UIImage imageNamed:#"x.png"];
}
-(void)Collision
{
if (CGRectIntersectsRect(Astronaut.frame, Landingarea.frame)) {
[self EndGame];
AstronautFire.hidden = YES;
RedBorder.hidden = NO;
AstronautCrashed.hidden = NO;
}
if (CGRectIntersectsRect(AstronautFire.frame, Landingarea.frame)) {
[self EndGame];
AstronautFire.hidden = YES;
RedBorder.hidden = NO;
AstronautCrashed.hidden = NO;
}
}
I'm just moving the frame up and down. At the bottom is landing area. When Astronaut and landing area frames touch, collision happens. But when I'm moving Astronaut up bigger image is shown (50x113) and when I'm moving Astronaut down smaller image is shown (50x85). When I'm near landing area and I press to go up bigger image shows and collision happens.

From the code samples, it really is hard to follow what you're trying to do. Notably, it's unclear how (or even if) you're animating the moving of the various views.
Whether you're animating or not, it's not clear from your code sample as to where AstronautMove is called. Did you mean to call that from touchesBegan and touchesEnded? But on the basis of what's been shared thus far, I don't see you calling AstronautMove and therefore don't see how you could possibly detect collisions.
Personally, I would have thought that you'd want to animate the moving of the views (it will render a more realistic and engaging moving of the views). And then, while an animation is underway, keep checking for a collision. In terms of how to "keep checking", you can use either a NSTimer or, even better, us a CADisplayLink (a mechanism to call a method each and every time the screen updates).
For example, you could do something like:
#interface ViewController ()
#property (nonatomic, strong) UIView *view1;
#property (nonatomic, strong) UIView *view2;
#property (nonatomic, strong) CADisplayLink *displayLink;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 50, 50)];
view1.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:view1];
self.view1 = view1;
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(50, 150, 50, 50)];
view2.backgroundColor = [UIColor darkGrayColor];
[self.view addSubview:view2];
self.view2 = view2;
}
#pragma mark - Handle touches
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self startAnimationTo:CGPointMake(50, 250) collisionChecking:YES];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self startAnimationTo:CGPointMake(50, 50) collisionChecking:NO];
}
#pragma mark - Handle starting and stopping of animation
- (void)startAnimationTo:(CGPoint)point collisionChecking:(BOOL)collisionChecking
{
if (collisionChecking)
[self startDisplayLink];
[UIView animateWithDuration:2.0 delay:0.0 options:0 animations:^{
CGRect frame = self.view1.frame;
frame.origin = point;
self.view1.frame = frame;
} completion:^(BOOL finished) {
// in case we never have collision, let's make sure we stop the display link
if (collisionChecking)
[self stopDisplayLink];
}];
}
- (void)stopAnimation
{
CALayer *layer = self.view1.layer.presentationLayer;
[self.view1.layer removeAllAnimations];
self.view1.frame = layer.frame;
[self stopDisplayLink];
}
#pragma mark - Handle the display link & check for collisions
- (void)startDisplayLink
{
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(checkForCollision:)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)stopDisplayLink
{
[self.displayLink invalidate];
self.displayLink = nil;
}
- (void)checkForCollision:(CADisplayLink *)displayLink
{
// Note, when checking for collision while an animation is underway, the `frame` of the
// view represents the final location of the view, not the current location. To get the
// current location, one has to grab the `presentationLayer`. So, we're going to get the
// `presentationLayer` of each of the views and use those to determine a collision.
CALayer *layer1 = self.view1.layer.presentationLayer;
CALayer *layer2 = self.view2.layer.presentationLayer;
if (CGRectIntersectsRect(layer1.frame, layer2.frame)) {
[self stopAnimation];
}
}
#end
Or, in iOS 7, you can use UIKit Dynamics to animate the movement of the views, identifying collisions programmatically using a UICollisionBehavior and assigning a collisionDelegate:
#interface ViewController () <UICollisionBehaviorDelegate>
#property (nonatomic, strong) UIView *view1;
#property (nonatomic, strong) UIView *view2;
#property (nonatomic, strong) UIDynamicAnimator *animator;
#property (nonatomic, strong) UISnapBehavior *snap;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 50, 50)];
view1.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:view1];
self.view1 = view1;
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(50, 150, 50, 50)];
view2.backgroundColor = [UIColor darkGrayColor];
[self.view addSubview:view2];
self.view2 = view2;
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
// create behavior that will detect collisions, calling the `UICollisionBehaviorDelegate`
// methods if and when collisions are detected
UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:#[view1, view2]];
collision.translatesReferenceBoundsIntoBoundary = YES;
collision.collisionDelegate = self;
[self.animator addBehavior:collision];
// in this example, I'm going to fix `view2` where it is, so it doesn't move when
// `view1` collides with it
UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:self.view2 attachedToAnchor:self.view2.center];
[self.animator addBehavior:attachment];
// finally, let's specify that neither view1 nor view2 should rotate when
// snapping, colliding, etc.
UIDynamicItemBehavior *noRotate = [[UIDynamicItemBehavior alloc] initWithItems:#[view1, view2]];
noRotate.allowsRotation = NO;
[self.animator addBehavior:noRotate];
}
- (void)addSnap:(CGPoint)point
{
[self removeSnap];
self.snap = [[UISnapBehavior alloc] initWithItem:self.view1 snapToPoint:point];
[self.animator addBehavior:self.snap];
[self.animator updateItemUsingCurrentState:self.view1];
}
- (void)removeSnap
{
if (self.snap) {
[self.animator removeBehavior:self.snap];
self.snap = nil;
}
}
#pragma mark - Handle touches
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self addSnap:CGPointMake(75, 225)];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self addSnap:CGPointMake(75, 75)];
}
#pragma mark - UICollisionBehaviorDelegate
// you can use these to be informed when there is a collision
- (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p
{
NSLog(#"%s", __FUNCTION__);
[self removeSnap];
}
- (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item1 withItem:(id<UIDynamicItem>)item2 atPoint:(CGPoint)p
{
NSLog(#"%s", __FUNCTION__);
[self removeSnap];
}
#end
Or, for a game, SpriteKit might be even better. You can google "SpriteKit example" and you'll probably find plenty of good introductions to SpriteKit.
I know that neither of the above examples are quite what you're doing, but hopefully it illustrates a couple of techniques for identifying collisions, which you could adapt for your app.

Related

how to set popover position horizontally

i am making an app i which i am using slider and on changing the position of slider value of slider is also sliding as well, now i am stuck that i want to set when i change postion of slider in horizontall form then i need to change that popover postion also in horizontall form. I am attaching a screen shot so that u people better understand it and this is my project link https://www.dropbox.com/s/n0fl34h6t8jlazn/CustomSlider.zip?dl=0,
below is my sample code on 1 view and i am changing my uislider class to anpopoverslider:
-(void)constructSlider {
_popupView = [[ANPopoverView alloc] initWithFrame:CGRectZero];
_popupView.backgroundColor = [UIColor clearColor];
_popupView.alpha = 0.0;
[self addSubview:_popupView];
}
and below is my ANpopoverslider
#import "ANPopoverSlider.h"
#implementation ANPopoverSlider
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self constructSlider];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self constructSlider];
}
return self;
}
#pragma mark - UIControl touch event tracking
-(BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
// Fade in and update the popup view
CGPoint touchPoint = [touch locationInView:self];
// Check if the knob is touched. If so, show the popup view
if(CGRectContainsPoint(CGRectInset(self.thumbRect, -12.0, -12.0), touchPoint)) {
[self positionAndUpdatePopupView];
[self fadePopupViewInAndOut:YES];
}
return [super beginTrackingWithTouch:touch withEvent:event];
}
-(BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
// Update the popup view as slider knob is being moved
[self positionAndUpdatePopupView];
return [super continueTrackingWithTouch:touch withEvent:event];
}
-(void)cancelTrackingWithEvent:(UIEvent *)event {
[super cancelTrackingWithEvent:event];
}
-(void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
// Fade out the popup view
[self fadePopupViewInAndOut:NO];
[super endTrackingWithTouch:touch withEvent:event];
}
#pragma mark - Helper methods
-(void)constructSlider {
CGRect frame = CGRectMake(150, 230, 300.0, 10.0);
_popupView = [[ANPopoverView alloc] initWithFrame:frame];
_popupView.backgroundColor = [UIColor clearColor];
_popupView.alpha = 0.0;
[self addSubview:_popupView];
}
-(void)fadePopupViewInAndOut:(BOOL)aFadeIn {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
if (aFadeIn) {
_popupView.alpha = 1.0;
} else {
_popupView.alpha = 0.0;
}
[UIView commitAnimations];
}
-(void)positionAndUpdatePopupView {
CGRect zeThumbRect = self.thumbRect;
CGRect popupRect = CGRectOffset(zeThumbRect, 0, -floor(zeThumbRect.size.height * 1.5));
_popupView.frame = CGRectInset(popupRect, -20, -10);
_popupView.value = self.value;
}
#pragma mark - Property accessors
-(CGRect)thumbRect {
CGRect trackRect = [self trackRectForBounds:self.bounds];
CGRect thumbR = [self thumbRectForBounds:self.bounds trackRect:trackRect value:self.value];
return thumbR;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
and here is my popover class
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.font = [UIFont boldSystemFontOfSize:15.0f];
UIImageView *popoverView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"sliderlabel.png"]];
[self addSubview:popoverView];
textLabel = [[UILabel alloc] init];
textLabel.backgroundColor = [UIColor clearColor];
textLabel.font = self.font;
textLabel.textColor = [UIColor colorWithWhite:1.0f alpha:0.7];
textLabel.text = self.text;
textLabel.textAlignment = NSTextAlignmentCenter;
textLabel.frame = CGRectMake(0, -2.0f, popoverView.frame.size.width, popoverView.frame.size.height);
[self addSubview:textLabel];
}
return self;
}
-(void)setValue:(float)aValue {
_value = aValue;
self.text = [NSString stringWithFormat:#"%4.2f", _value];
textLabel.text = self.text;
[self setNeedsDisplay];
}
I tried the sample project and work with simple function
#property (strong, nonatomic) IBOutlet UISlider *slider; // make the getter and setter for Slider
#property (strong, nonatomic) IBOutlet UILabel *lblText; // make the getter and setter for label
- (void)viewDidLoad {
[super viewDidLoad];
// set verticical of UIslider
CGAffineTransform trans = CGAffineTransformMakeRotation(M_PI * 0.5);
self.slider.transform = trans;
// get the events of UISlider
[self.slider addTarget:self
action:#selector(sliderDidEndSliding:)
forControlEvents:(UIControlEventTouchUpInside | UIControlEventTouchUpOutside)];
}
// this method used for hide the label after changed the value
- (void)sliderDidEndSliding:(NSNotification *)notification {
NSLog(#"Slider did end sliding...");
[self.lblText removeFromSuperview];
}
// the slider value change method
- (IBAction)slider:(UISlider*)sender
{
// add the subview the lable to slider
[self.slider addSubview:self.lblText];
self.lblText.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"sliderlabel.png"]];
self.lblText.text = [NSString stringWithFormat:#"%4.2f",sender.value];
// change the label position depend upon slider move
self.lblText.center = CGPointMake(self.slider.value*self.slider.bounds.size.width,80);
[self.lblText setTransform:CGAffineTransformMakeRotation(-M_PI / 2)];
}
here I attached the sample project for UISlider the download link

UITouch methods in an object not working properly

I have got a SKScene name “Scene” in which I instantiate 2 objects of my class “Button” subclass of SKNode.
In order to not multiply the number of lines of code in my SKScene, I wanted to implemente the touch methods directly in my class “Button”.
Here is the code :
Scene.h
#import <SpriteKit/SpriteKit.h>
#interface Scene : SKScene
#end
Scene.m
#import "Scene.h"
#import "Button.h"
#implementation Scene
- (id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
Button *button01 = [Button node];
[button01.number setString: #"1"];
button01.position = CGPointMake(CGRectGetMidX(self.frame) - 50, 160);
Button *button02 = [Button node];
[button02.number setString: #"2"];
button02.position = CGPointMake(CGRectGetMidX(self.frame) + 50, 160);
[self addChild:button01];
[self addChild:button02];
}
return self;
}
#end
Button.h
#import <SpriteKit/SpriteKit.h>
#interface Button : SKNode
#property (strong, nonatomic) NSMutableString *number;
#end
Button.m
#import "Button.h"
SKShapeNode *button;
#implementation Button
- (id)init
{
if (self = [super init])
{
self.userInteractionEnabled = YES;
_number = [[NSMutableString alloc] init];
[_number setString: #"0"];
button = [SKShapeNode node];
[button setPath:CGPathCreateWithRoundedRect(CGRectMake(-25, -25, 50, 50), 4, 4, nil)];
button.fillColor = [SKColor clearColor];
button.lineWidth = 1.0;
button.strokeColor = [SKColor whiteColor];
button.position = CGPointMake(0, 0);
SKLabelNode *label = [SKLabelNode labelNodeWithFontNamed:#"Arial"];
label.text = _number;
label.fontSize = 20;
label.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;
label.position = CGPointMake(0, 0);
label.fontColor = [SKColor whiteColor];
[button addChild:label];
[self addChild:button];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if(CGRectContainsPoint(button.frame, location))
{
button.fillColor = [SKColor whiteColor];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
button.fillColor = [SKColor clearColor];
}
#end
The problem is when I touch inside the button01, it’s the button02 color’s which change. As if the action is only apply on the last instance of my class.
How can I fixe this.
Thanks in advance.
The issue is the following variable has global scope in your Button class:
SKShapeNode *button;
Since it is shared among the instances of Button, it contains a reference to the SKShapeNode of the last Button that was instantiated. In this case, button 2. You can resolve this issue by defining button as an instance variable:
#implementation Button
{
SKShapeNode *button;
}
...
For some reasons your Button has SKNode as a superclass. SKNode doesn't have a size property, which you can change, so it takes the whole size of it's parent node. Consider it as a layer of the scene. So wherever you touch, the latest SKScene's child (which is button02 in your case) will receive the touch.
Solution: Define Button as a subclass of SKShapeNode directly.

Using UIKit's UIScrollView with SpriteKit

I read two questions here about that, both with the same answer. The suggested solution was to create the UIScrollView object, and then add it to the parent view of the SKScene in the target scene's didMoveToView:, removing it in willMoveFromView:.
And that is the target scene code I implemented:
#interface MQSSMakerScene ()
#property BOOL contentCreated;
#property MQSSMakerWorkspaceLayer *workspaceLayer;
#property MQSSMakerDockLayer *dockLayer;
#property UIScrollView *scrollView;
#end
#implementation MQSSMakerScene
- (id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size]) {
CGSize layerSize = CGSizeMake(944, 140);
CGPoint layerPosition = CGPointMake(40, 768-(140+30));
CGRect viewFrame = CGRectMake(layerPosition.x, layerPosition.y, layerSize.width, layerSize.height);
_scrollView = [[UIScrollView alloc] initWithFrame:viewFrame];
_scrollView.contentSize = CGSizeMake(2000, 120);
_scrollView.scrollEnabled = YES;
_scrollView.showsHorizontalScrollIndicator = YES;
_scrollView.backgroundColor = [UIColor brownColor];
}
return self;
}
- (void)didMoveToView:(SKView *)view
{
[super didMoveToView:view];
if(!self.contentCreated) {
[self createSceneContents];
self.contentCreated = YES;
}
[self.view addSubview:_scrollView]; // --> WHERE IT'S BEING ADDED
}
- (void)willMoveFromView:(SKView *)view
{
[super willMoveFromView:view];
[_scrollView removeFromSuperview]; // --> WHERE IT'S BEING REMOVED
}
- (void)createSceneContents
{
self.backgroundColor = [UIColor colorWithHue:.237 saturation:.56 brightness:.46 alpha:1];
self.scaleMode = SKSceneScaleModeAspectFill;
[self addChild:[self newMakerLayout]];
}
- (SKNode *)newMakerLayout
{
SKNode *mainLayout = [[SKNode alloc] init];
self.workspaceLayer = [[MQSSMakerWorkspaceLayer alloc] init];
self.dockLayer = [[MQSSMakerDockLayer alloc] init];
[mainLayout addChild:self.workspaceLayer];
[mainLayout addChild:self.dockLayer];
MQSSStoryObject *ob1 = [[MQSSStoryObject alloc] initWithImageNamed:#"maker-1.png"];
[self.workspaceLayer addChild:ob1];
return mainLayout;
}
#end
Please note that the user should go to this scene from the home scene when clicking on a button. The problem now is that once I add the line:
[self.view addSubview:_scrollView];
to add the UIScrollView object to this scene, the application no more goes to this scene and instead add the UIScrollView to the home scene I am transitioning from. It also doesn't remove it when transitioning to another scene. Once I comment out this line, everything works just as expected, clearly without presenting the UIScrollView.
I am stuck. Any help or advice is highly appreciated. Thanks!
I finally figured out what the problem was for me. I was using the -(void)willLayoutSubviews method of the viewController to ensure I had the correct bounds, but I had forgotten to see if my SKScene was already presented. That resulted in a new welcomeScene being presented each time the view was laid out on top of the old one.
-(void)willLayoutSubviews
{
if(!self.didPresentScene)
{
// Present scene here
....
self.didPresentScene = YES;
}
}

How to implement "finger-tracing" layer in app like the iOS Simulator

Now that our app has shipped, our person in charge of training has a request:
"The app is cool, but we need a mode showing the movement of the fingers, like how gestures show up in the Simulator or iPad's laser pointer mode in Keynote [so we can capture films]."
This is an app that uses a UITabBarController with xibs for each tab (4). This is a pretty complicated app with interacting gesture recognizers and I was having "first, do no harm" nightmares...
I tried adding a simple "global UIView" above the tab controller using the scheme here: http://www.james-vandyne.com/creating-universal-overlays-using-uiviews-on-ios/
My "PresentationView" attempt:
in my app delegate:
UIWindow *mainWindow = [[UIApplication sharedApplication] keyWindow];
[self setPresentationView:[[PresentationView alloc] initWithFrame: [mainWindow frame]]];
[mainWindow insertSubview:presentationView aboveSubview:mainWindow];
The class:
// PresentationView.h
#import <UIKit/UIKit.h>
#interface PresentationView : UIView
{
NSMutableDictionary *touchesInView;
}
#property (nonatomic, retain) NSMutableDictionary *touchesInView;
#end
#import "PresentationView.h"
#import "TouchPoint.h"
#implementation PresentationView
#synthesize touchesInView;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[ self setAlpha:0.1];
[self setBackgroundColor:[UIColor whiteColor]];
[self setUserInteractionEnabled:YES];
[self setMultipleTouchEnabled:YES];
touchesInView = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void) dealloc
{
[touchesInView release];
touchesInView = nil;
[super dealloc];
}
- (void)drawRect:(CGRect)rect
{
if ([touchesInView count] < 1)
return;
CGContextRef context = UIGraphicsGetCurrentContext();
NSEnumerator *touchEnum = [touchesInView objectEnumerator];
TouchPoint *nextTouch;
float rad = 24;
while (nextTouch = [touchEnum nextObject]) {
[[ UIColor redColor] set];
CGContextAddArc(context, nextTouch.current.x, nextTouch.current.y, rad, 0.0, M_PI*2, 1);
CGContextFillPath(context);
CGContextStrokePath(context);
}
}
- (UIView *) hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
[self setNeedsDisplay];
return [[[[[UIApplication sharedApplication] keyWindow] subviews] objectAtIndex:0] hitTest:point withEvent:event];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for( UITouch *t in touches )
{
NSValue *key = [NSValue valueWithPointer:t];
CGPoint loc = [t locationInView:self];
TouchPoint *newTouch = [[TouchPoint alloc] init];
[newTouch setBegan:loc];
[newTouch setCurrent:loc];
[newTouch setTapCount:[t tapCount]];
[touchesInView setObject:newTouch forKey:key];
[newTouch release];
}
[self setNeedsDisplay];
[[[[[UIApplication sharedApplication] keyWindow] subviews] objectAtIndex:0] touchesBegan:touches withEvent:event];
}
// More touch methods- all ignored
This kinda works- the view sits atop all the other views, and hitTest:withEvent: fires, and I was successfully drawing a red circle at the hit point in drawRect:.
But it breaks down when I try to track touches- touchesBegan/Moved/Ended don't fire. (Yes, I have turned on UserInteractionEnabled and setMultipleTouchEnabled for this global view). Fortunately, I haven't screwed up gesture recognition on anything below- the other views are getting events, and the app is behaving normally under this global view.
Normally I use IB to build/locate views and don't build them in code from scratch, so it's very possible there's (a?/several?) simple UIView properties I'm not setting up right... but I can't see it. Or am I going to get myself in trouble with this, trying to forward events down the chain?
There's a good framework called FingerTips that does this.
It's also easy to implement and it only shows the circles if there is an external display so you are presenting it.

iOS touchesBegan being overridden by UIScrollView. Not a delay issue. Can't use gesture recognizer in this case

So I read quite a bit, but still I can't find the solution.
I have a UIViewController which is creating (programatically) a UIScrollView, which Contains a UIView and a UIImage. The UIView lies on top of the rest.
This UIView generates some UIImageViews which I need to get feedback from when tapped. I need to know which image was tapped by getting their tags. That's why I can't use gesture recognizer, since it can only be called on one view.
If I call this:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
NSLog(#"tag=%#", [NSString stringWithFormat:#"%i", touch.view.tag]);
}
On the view (called GraphView, which has it's own class) I get what I need. Still, I need to do this from the ViewController side because I have to open modal window, navigation controllers, etc... If I use that same code on the ViewController nothing happens. If I disable User Interaction on the UIScrollView it works. If I disable the delay on the UIScrollView nothing happens. No matter how long you press you get nothing. touchesBegan doesn't get called at all even if the delay is enabled.
Here's the part of the implementation of the ViewController where I generate the Views:
// ScrollView
CGRect frame = CGRectMake(0, 0, 480, 320);
myScrollView = [[UIScrollView alloc] initWithFrame:frame];
myScrollView.backgroundColor = [UIColor blackColor];
myScrollView.showsVerticalScrollIndicator = YES;
myScrollView.showsHorizontalScrollIndicator = YES;
myScrollView.userInteractionEnabled = YES;
myScrollView.contentSize = CGSizeMake(SCROLLVIEW_WIDTH, SCROLLVIEW_HEIGHT);
myScrollView.delegate = self;
[self.view addSubview:myScrollView];
// Add UIImage for background
UIImageView *backgroundGraph = [[UIImageView alloc] initWithFrame:CGRectMake (0,0,SCROLLVIEW_WIDTH,SCROLLVIEW_HEIGHT)];
backgroundGraph.image = [UIImage imageNamed:#"graph_background.png"];
backgroundGraph.userInteractionEnabled = YES;
[myScrollView addSubview:backgroundGraph];
//[self.view addSubview:backgroundGraph];
[backgroundGraph release];
// Add View for Graph.
GraphView *graphViewC = [[GraphView alloc] init];
self.graphView = graphViewC;
graphView.tag = 200;
graphView.userInteractionEnabled = YES;
graphView.frame = CGRectMake(0, 0, SCROLLVIEW_WIDTH, SCROLLVIEW_HEIGHT);
graphView.backgroundColor = [UIColor clearColor];
[myScrollView addSubview:graphView];
//[self.view addSubview:graphView];
.h file on ViewController looks like this:
#import <UIKit/UIKit.h>
#class GraphView;
#interface TrackingViewController : UIViewController <UIScrollViewDelegate> {
UIScrollView *myScrollView;
GraphView *graphView;
int someNum;
#define SCROLLVIEW_HEIGHT 273
#define SCROLLVIEW_WIDTH 599
}
#property (nonatomic, retain) GraphView *graphView;
- (void) openModal;
//- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer;
#property (nonatomic, retain) UIScrollView *myScrollView;
#end
As always, I am thankful to everyone who can help with any ideas(and I've gotten a lot of help here always, so thanks in advance :-) ).

Resources