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

-(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?

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.

How to pass touch event to another object?

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.

iOS Loses Touches?

I can't find anything to explain lost UITouch events. If you smash your full hand on the screen enough times, the number of touchesBegan will be different than the number of touchesEnded! I think the only way to actually know about these orphaned touches will be to reference them myself and keep track of how long they haven't moved.
Sample code:
int touchesStarted = 0;
int touchesFinished = 0;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
touchesStarted += touches.count;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
touchesFinished += touches.count;
NSLog(#"%d / %d", touchesStarted, touchesFinished);
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
Don't forget about touchesCancelled: UIResponder reference
Editing in response to the poster's update:
Each touch object provides what phase it is in:
typedef enum {
UITouchPhaseBegan,
UITouchPhaseMoved,
UITouchPhaseStationary,
UITouchPhaseEnded,
UITouchPhaseCancelled,
} UITouchPhase;
I believe that if a touch starts and ends in the same touch event set, -touchesBegan:withEvent: will be called but will contain touches which have ended or cancelled.
You should change your counting code, then, to look like this:
int touchesStarted = 0;
int touchesFinished = 0;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self customTouchHandler:touches];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self customTouchHandler:touches];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self customTouchHandler:touches];
}
- (void)customTouchHandler:(NSSet *)touches
{
for(UITouch* touch in touches){
if(touch.phase == UITouchPhaseBegan)
touchesStarted++;
if(touch.phase == UITouchPhaseEnded || touch.phase == UITouchPhaseCancelled)
touchesFinished++;
}
NSLog(#"%d / %d", touchesStarted, touchesFinished);
}
Every single touch event will go through both phases of started and finished/cancelled, and so your counts should match up as soon as your fingers are off the screen.
One thing to remember... You may receive some touches that have multiple taps. Don't forget to take tapCount into account.
However, if you still have the problem, you can consider all touches from the event, though it presents some other management issues...
HACK ALERT
I have coded the following HACK to work around this. Sometimes the touchesEnded does not get called, BUT, the touches show up as part of all the touches in the event.
Note, that you can now process the same "canceled" or "ended" touch multiple times. If that is a problem, you have to keep your own state of "pending" touches, and remove them when done.
Yeah, it all is pretty bad, but I don't know how to overcome this issue without a similar hack. The basic solution is to look at all the touches in each event, and process them based on their phase, calling the appropriate ended/canceled when they are seen.
- (void) touchesEndedOrCancelled:(NSSet *)touches
{
__block NSMutableSet *ended = nil;
__block NSMutableSet *canceled = nil;
[touches enumerateObjectsUsingBlock:^(UITouch *touch, BOOL *stop) {
if (touch.phase == UITouchPhaseEnded) {
if (!ended) ended = [NSSet setWithObject:touch];
else [ended addObject:touch];
} else if (touch.phase == UITouchPhaseCancelled) {
if (!canceled) canceled = [NSSet setWithObject:touch];
else [canceled addObject:touch];
}
}];
if (ended) [self touchesEnded:ended withEvent:nil];
if (canceled) [self touchesCancelled:canceled withEvent:nil];
}
Then, call it at the end of touchesBegan and touchesMoved...
[self touchesEndedOrCancelled:event.allTouches];
For this to work, touchesEnded/Canceled needs to not choke on a nil event. Also, the "other" needs to be handled. In touchesEnded...
[self touchesCancelled:[event.allTouches objectsPassingTest:^BOOL(UITouch *touch, BOOL *stop) {
return touch.phase == UITouchPhaseCancelled;
}] withEvent:nil];
and in touchesCanceled...
[self touchesEnded:[event.allTouches objectsPassingTest:^BOOL(UITouch *touch, BOOL *stop) {
return touch.phase == UITouchPhaseEnded;
}] withEvent:nil];
You may need to provide more detail but....
If you run your finger off the edge of the screen this event will show touch started and touch moved but no end as it didn't actually end (lift finger). This could be your problem, that the event didn't happen. Plus there is a limit to the amount of touches in multi touch if you press say 10 times its then up to the system to determine what events are really and what are false, it seems like you are using the hardware incorrectly.

How to include a hyperlink in a label in Cocoa Touch?

I'm trying to find a simple way to include a hyperlink within the text of a label in my iOS app. The goal is to have the user tap the URL and the app will open a Safari browser with that URL.
I've read about including a button with the URL as the label, but that's not going to work for my application.
Is there a simple way to do this?
Thanks so much
You can achieve this by using NSArrtibutedStrings — but I would recommend to use some wrapper around this C-functions. I like OHAttributedLabel.
The demo included shows exactly, how hyperlinks can be handled.
Instead of calling Safari you could start a UIWebView. You have more control about the actions the user can do at that web page.
You need to enable user interactions for your label and then override the - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event method to handle the touch.
To enable user interactions set the following property on your UILabel:
urlLabel.userInteractionEnabled = YES;
An example of touchedEnded:WihEvent: in your UIViewController:
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * touch;
CGPoint currPt;
if ((touches = [event touchesForView:urlLabel]))
{
touch = [touches anyObject];
currPt = [touch locationInView:self.view];
if ( (currPt.x >= urlLabel.frame.origin.x) &&
(currPt.y >= urlLabel.frame.origin.y) &&
(currPt.x <= (urlLabel.frame.origin.x + urlLabel.frame.size.width)) &&
(currPt.y <= (urlLabel.frame.origin.y + urlLabel.frame.size.height)) )
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlLabel.text]];
return;
};
};
return;
}

Time between touch began and touch ended

Is there any method in objective-c to find the time between touch began and touch ended??
// add this ivar to your view controller
NSTimeInterval lastTouch;
// assign the time interval in touchesBegan:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
{
lastTouch = [event timestamp];
}
// calculate and print interval in touchesEnded:
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
{
NSTimeInterval touchBeginEndInterval = [event timestamp] - lastTouch;
NSLog(#"touchBeginEndInterval %f", touchBeginEndInterval);
}
Each UITouch has it's own time/date stamp. Compare the ones you're interested in. Take a looke at the UIResponder class ref.
Aside- SO needs to update their code or release an iPhone app. Typing into their javascriptoided out text fields with an iPhone is almost comical.
In your touchesBegan:withEvent: method, create an NSDate object and store it in an instance variable. (For non-debugging purposes, create one date per touch and use CFMutableDictionary to associate the date with the touch.) Then, in touchesEnded:withEvent:, retrieve the stored date and create a new date, and send the latter a timeIntervalSinceDate: message to subtract the older date from it, giving you the result in seconds.