How to pass touch event to another object? - iphone

I referenced the apps called "Comic Strip" and "Balloon Stickies Free"
When i add a speech balloon and touch s.b or s.b's tail, it works. But when i touch tail's around or between s.b and s.b's tail, it doesn't work. And Photo gets touch and works below the s.b.
So i tried to use hitTest:withEvent.
It works when i touch rectangle or tailRect first time. But when i touch other place in the object, and i touch rectangle or tailRect again, it doesn't work.
So how to modify this code ? i don't know .. help me please
- (id)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *hitView = [super hitTest:point withEvent:event];
if(CGRectContainsPoint(rectangle, currentPt)==YES || CGRectContainsPoint(tailRect, currentPt)==YES)
return hitView;
else
return nil;
}

Try overriding - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event instead.
Or take a look at Ole Begemann's OBShapedButton. Code can easily be modified
to work with UIView instead of UIButton.

See this post horizontal scrolling. Using this code you can get all touch events in a single UIWindow class. You have to write some code to pass control appropriately.

Related

get timespan of swipe action in iPhone app

How can we get the time a user spent to finish a swipe right or swipe left action? Already googled but no luck. If there is not built-in solution already, will touch begin and touch end together work?
Measure the start and end time, and calculate the difference in the UIGestureRecognizer callback method for gestureRecognizer.state == UIGestureRecognizerStateBegan and gestureRecognizer.state == UIGestureRecognizerStateEnded
You can do this by getting the date (which you create as ivar or property) in the touchesBegan method like this:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
touchStartDate = [NSDate date];
}
Then you fetch the difference in the touches end method:
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSTimeInterval *touchDuration = [[NSDate date] timeIntervalSinceDate:touchStartDate];
NSLog(#"Touchduration %f",touchDuration);
}
If you only want to get the duration of a swipe left/right gesture you also need to check if the x value of the touch changed. This should be easy.

(cocos2d sneaky input) when setting joystick position with touchLocation, sprite won't move

i want to let user choose where the joystick should be. i.e., when user touch at one location, the joystick will appear there and ready to use and will remove when finger released.
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if ([self getChildByTag:kTagJoyStick] == nil) {
[self addJoystickWithPosition:[Helper locationFromTouches:touches]];
}
}
-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if ([self getChildByTag:kTagJoyStick] != nil) {
[self removeChildByTag:kTagJoyStick cleanup:YES];
}
}
-(void) ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[self ccTouchesEnded:touches withEvent:event];
}
(do nothing in ccTouchesMoved method)
the update methods for joystick is:
-(void) sneakyUpdate {
if ([self getChildByTag:kTagJoyStick] != nil) {
if (joystick.velocity.x < 0) {
[self controlLeft];
}
else if (joystick.velocity.x > 0) {
[self controlRight];
}
else {
[self controlStop];
}
}
else {
[self controlStop];
}
}
but the result is, the joystick will appear and auto remove. but my sprite won't move. ( i set the break point, the sneakyUpdate method did get called. but the joystick.velocity is always 0. (and the thumbSprite didn't follow our finger.
please help me.
update:
and it turns out that i have to use 2 fingers (one for touch once and let the joystick show up, move my finger away, and then use another finger to control the joystick)
I'm not 100% sure, but I think you should use ccTouchBegan instead ccTouchesBegan, because sneakyJoystick classes use ccTouchBegan/Moved/Ended/Cancelled. Also, there are for a single touch, that is what you want.
I hope it works!
It looks like the problem is in your joystick class. Every joystick implementation I've seen uses the ccTouchesBegan method to activate the joystick, then in the ccTouchesMoved method, it makes sure its activated before using it. The problem I am seeing is that you create and add the joystick AFTER the touches began method, meaning your joystick never 'activates'. One way of bypassing this is to do all of the joystick's ccTouchesBegan functions in the method that creates the joystick, and 'activate' it from there by passing a reference to the touch that will be using it.

UIImageView scope. Accessing from another class

Here's part of the code I'm working with: http://pastie.org/2472364
I've figured out how to access the UIImageView from another method within the same class file in which it was programmatically created.
However, I was wondering how I'd access that same UIImageView from within the LetterTiles.m file, specifically within the touchesMoved method. The way I wrote the code in the sample, it will only show if the frames intersect if they're on top of each other when the otherMethod is called. Of course, I need to be able to check if the views intersect within the actual touchesMoved method. I'm sure it's something super easy, but I'm just not sure how to do it.
Thanks in advance for any help you can give me.
From your comment, and using the code you already have, I would go down this route. This isn't what I would do personally, just FYI. The structure is a bit shakey with the way it sounds like you want this.
Create the place holder UIImageView in the touchesBegan function, then check to see if they intersect when the user stops moving the image.
#import "LetterTiles.h"
#implementation LetterTiles
#synthesize placeHolder;
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
// Retrieve the touch point (I consider this useful info to have, so I left it in)
CGPoint pt = [[touches anyObject] locationInView:self];
startLocation = pt;
// Create a place holder image wherever you want
[self setPlaceHolder:[[[UIImageView alloc] initWithFrame:CGRectMake(39, 104, 70, 70)] autorelease]];
[newImage setImage[UIImage imageNamed:#"placeHolder.png"]] autorelease];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint pt = [[touches anyObject] locationInView:[self superview]];
[self setCenterPoint:pt];
}
-(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
LetterTiles *movingTile = self;
if (CGRectIntersectsRect([movingTile frame], [placeHolder frame])) {
NSLog(#"Touched");
[self setFrame:[placeHolder frame]];
}
}
Make a protocol called ViewMoved which will contain one method otherMethod.
implement that in myMainViewController
take a delegate property of type ViewMoved in LetterTiles.
Assign self when you make new object of type LetterTiles in myMainViewController.
On every movement of touch call oherMethod of delegate and check whether any views of type LetterTiles are intersecting or not.
This will catch any intersection when any of the view is moved.....
If above is not matching with your question then write here......

Putting UIButton and other UIControl objects inside an MKAnnotationView and allowing user interaction

I have a custom annotation view on the map, which has a UIButton in it, but the UIButton is not responsive when pressed. I have two main problems with user interaction on the annotation view:
Buttons and other controls are not responsive.
I want the annotation to block touches according to my implementation of - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event - that is if I return YES then I don't want the touches to get sent through to the MKMapView (potentially selecting other annotations that are BEHIND my annotation view), I want to handle the touch myself in this case.
I have made sure userInteractionEnabled is set to YES and I have investigated how touches are sent to the custom annotation view (my subclass of MKAnnotationView) by overriding touchesBegan etc. - but it appears that the touches are usually cancelled (thought I've managed to get touchesEnded a few times) - so it seems like it will even be difficult to manually implement any user-interaction with the custom annotation view.
Does anyone have any insights into allowing more user interaction with MKAnnotationView objects?
I managed to resolve this with the help of a colleague. The solution is to override - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event. Our assumption is that MKAnnotationView (which your annotation view must inherit from) overrides this to do the 'wrong' thing (presumably so that annotation selection doesn't get blocked between overlapping annotations). So you have to re-override it to do the right thing and return the appropriate UIView, the system will then send the events to it and the user will be able to interact with it :). This has the beneficial (in this case) side-effect that the interactive annotation blocks the selection of annotations that are behind it.
I found that rather than overriding hitTest:withEvent: I could just override pointInside:withEvent: instead and just get it to return YES. I guess that officially I should be doing a point-rect intersect check to ensure the place I'm tapping is within the control element, but in practise, just putting return YES appears to work perfectly well, still allowing you to dismiss the MKAnnotationView by tapping away from it.
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
// for testing purposes
BOOL result = [super pointInside:point withEvent:event];
NSLog(#"pointInside:RESULT = %i", result);
return YES;
}
Adding up to the answer of jhabbott, this is what worked for me. I have a custom annotation view MKCustomAnnotationView that holds a custom annotation CustomPin as annotation. That 'pin' holds a UIButton as accessory button replacement which I wanted to get touch events.
My hitTest method would look like this:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *result = [super hitTest:point withEvent:event];
//NSLog(#"ht: %f:%f %d %#", point.x, point.y, [[event touchesForView:self] count], result);
if ([result isKindOfClass:[MKCustomAnnotationView class]])
{
MKCustomAnnotationView *av = (MKCustomAnnotationView *)result;
CustomPin *p = av.annotation;
UIButton *ab = p.accessoryButton;
if (p.calloutActive && point.x >= ab.frame.origin.x)
return ab;
}
return result;
}
The calloutActive bool is probably not necessary in most cases.
For anyone looking to add a tapGesture to an AnnotationView subview then the answer at the bottom of this:
MKannotationView with UIButton as subview, button don't respond
Worked for me:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (CGRectContainsPoint(_button.frame, point)) {
return _button;
}
return [super hitTest:point withEvent:event];
}

Is it possible to have a "touchesBegan" on a UITableViewCell?

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
touchStartTime = [event timestamp];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSTimeInterval touchTimeDuration = [event timestamp] - touchStartTime;
}
touchStartTime is defined at class level.
Any idea why this won't recognise the touch events?
Thanks for the help!
Yes, this is possible to do. I setup a test project with a custom UITableViewCell subclass and defined the methods in the same way that you have, adding a log to the touchesEnded to print the touchTimeDuration. I ran it in the simulator and it seems to work for me.
How are you determining if your code is recognizing the events?
Personally, from my experience with the UITableView, I don't think that you can use the touch events.
You may have to look into other ways of dealing with this. For example, try using the selection as a helper?