Delay Touch Response - iphone

I have a variable called touchStatus that tracks the touch status in the program. The variable gets set to B in the touchesBegan method, E in touchesEnded and to M in touchesMoved.
However, my requirements are a little different. I was requested to program in a way so that there is one second of delay between the finger being lift off from the screen and touchStatus getting set to E. If the user touches the screen before the one second elapses, touchStatus should continue to be M or B (whatever it was before the one second).
How can I accomplish this?

You can use
[self performSelector:#selector(setEndedValue:) withObject:self afterDelay:1.0];
Create a BOOL to monitor whether the value should be set such as:
BOOL hasTouchRestarted = NO;
If the screen is touched again before the value is set, change the value to YES and return from the setEndedValue method.
-(void)setEndedValue {
if ( hasTouchRestarted ) { return; }
// set value
self.touchStatus = E;
}

In the touchEnded routine set up an NSTimer task to invoke a selector in one second. If there is another touch before then, cancel the timer task.

Use a NSTimer *timer ivar to initiate a delayed call, and cancel the call if the user lifts the finger before one second.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.myvar = #"B";
[self.timer invalidate];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(handleOneSecondPress) userInfo:nil repeats:NO];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent*)event {
[self.timer invalidate];
self.timer = nil;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
self.myvar = #"M";
}
- (void)handleOneSecondPress {
self.timer = nil;
self.myvar = #"E";
}

Related

Make a button visible after some time with NSTimer

I'm trying to develop a new application for iOS but I'm stuck with NSTimer :-(. Currently I have a void function which hides an UIButton after the user taps twice or more on the screen and a NSTimer. I want to make the button visible again after the NSTimer reaches 5 seconds and stop and reset it right after in order to re-hide it after the user taps twice again :-) but I don't know how to tell the app that 5 seconds have passed :-/.
Can someone help me, please? :-)
Here's the code so far :-)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSUInteger numTaps = [[touches anyObject] tapCount];
if (numTaps >= 2)
{
// Other code//
[self.button setHidden:YES];
buttonHideTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 invocation:nil repeats:NO];
// Other code //
}
}
Thanks!
The timer needs to have a selector, which will tell the timer what to do after the time has passed:
buttonHideTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(showButtonNow) userInfo:nil repeats:NO];

How to Implement Touch Up Inside in touchesBegan, touchesEnded

I'm wondering if someone knows how to implement the "touch up inside" response when a user pushes down then lifts their finger in the touchesBegan, touchesEnded methods. I know this can be done with UITapGestureRecognizer, but actually I'm trying to make it so that it only works on a quick tap (with UITapGestureRecognizer, if you hold your finger there for a long time, then lift, it still executes). Anyone know how to implement this?
Using the UILongPressGesturizer is actually a much better solution to mimic all of the functionality of a UIButton (touchUpInside, touchUpOutside, touchDown, etc.):
- (void) longPress:(UILongPressGestureRecognizer *)longPressGestureRecognizer
{
if (longPressGestureRecognizer.state == UIGestureRecognizerStateBegan || longPressGestureRecognizer.state == UIGestureRecognizerStateChanged)
{
CGPoint touchedPoint = [longPressGestureRecognizer locationInView: self];
if (CGRectContainsPoint(self.bounds, touchedPoint))
{
[self addHighlights];
}
else
{
[self removeHighlights];
}
}
else if (longPressGestureRecognizer.state == UIGestureRecognizerStateEnded)
{
if (self.highlightView.superview)
{
[self removeHighlights];
}
CGPoint touchedPoint = [longPressGestureRecognizer locationInView: self];
if (CGRectContainsPoint(self.bounds, touchedPoint))
{
if ([self.delegate respondsToSelector:#selector(buttonViewDidTouchUpInside:)])
{
[self.delegate buttonViewDidTouchUpInside:self];
}
}
}
}
I'm not sure when it was added, but the property isTouchInside is a life saver for any UIControl derived object (e.g. UIButton).
override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
super.endTracking(touch, with: event)
if isTouchInside {
// Do the thing you want to do
}
}
Here's the Apple official docs
You can implement touchesBegan and touchesEnded by creating a UIView subclass and implementing it there.
However you can also use a UILongPressGestureRecognizer and achieve the same results.
I did this by putting a timer that gets triggered in touchesBegan. If this timer is still running when touchesEnded gets called, then execute whatever code you wanted to. This gives the effect of touchUpInside.
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSTimer *tapTimer = [[NSTimer scheduledTimerWithTimeInterval:.15 invocation:nil repeats:NO] retain];
self.tapTimer = tapTimer;
[tapTimer release];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([self.tapTimer isValid])
{
}
}
You can create some BOOL variable then in -touchesBegan check what view or whatever you need was touched and set this BOOL variable to YES. After that in -touchesEnded check if this variable is YES and your view or whatever you need was touched that will be your -touchUpInside. And of course set BOOL variable to NO after.
You can add a UTapGestureRecognizer and a UILongPressGestureRecognizer and add dependency using [tap requiresGestureRecognizerToFail:longPress]; (tap and long press being the objects of added recognizers).
This way, the tap will not be detected if long press is fired.

Call a function if userinteraction is nil for 3 seconds

Guys i need to call a function in such a view that if there is no user interaction for three seconds the function should be called
what should i do?
Can any one pls give a logic or link which help this?
Thanks
My recommendation is to override - (void)touchesBegan: withEvent: on that view.
When you receive a touch event, set a timer, and make its time 3 seconds. If you receive a touch and there is a timer, change its fire date to be 3 seconds after the touch time. When the timer fires, call the function, and set the timer to nil.
You can play with the movement, removals and cancellation methods to make your timer fire correctly and at the right time for the activity required.
Use NSTimer as:-
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self.view];
if ([touch view] == self.view)
{
NSTimer *updateTimer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:#selector(updateTime) userInfo:nil repeats:YES];
}
}
-(void)updateTime
{
NSLog(#"....Update Function Called....");
[self functionName];
}
Use this for calling function.Check it Hope it helps.Thanks :)

Measuring the time taken when shaking device

I am developing an application that measures the total time of a shake event. In other words, the timer starts when the shake event is started, and the timer stops when the shake event ends.
So my question is, if we hold two iTouches in a single hand and then shake both at the same time, will the shake event generate the same value on both iTouches?
This is my code:
-(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake) {
timer = [NSTimer scheduledTimerWithTimeInterval:0.00025 target:self selector:#selector(showactivity) userInfo:nil repeats:YES];
}
}
-(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake) {
[timer invalidate];
}
}
I'd just make an instance variable of type NSDate called shakesBegan, or whatever. Then just call this in motionBegan:
-(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake) {
shakesBegan = [NSDate date];
}
}
-(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake) {
NSDate *shakesFinished = [NSDate date];
NSTimeInterval shakeTime = [shakesFinished timeIntervalSinceDate:shakesBegan];
NSLog(#"Shaken for %f seconds",shakeTime);
}
}
The output should say something like Shaken for 1.233242 seconds. However, I don't have a device to test this so your mileage may vary.
The reason you're getting an error is because you must make shakesBegan an instance variable. Like this in your interface:
#interface Something : UIViewController
{
NSDate *shakesBegan;
}
#end

Anyone have code to substitute for UILongPressGestureRecognizer?

I'd like to support pre 3.2 and this is the only symbol that doesn't want to cooperate, anyone know of some touchesmoved code or something i can use in lieu of the UILongPressGestureRecognizer?
Thanks,
Nick
As you know, you should use touchesBegan, Moved, Ended, and Canceled functions for pre 3.2 iOS.
I think implementing only touchesMoved is bad because if the user presses and doesn't move at all until releasing, then touchesMoved won't get called ever.
Instead, I used NSTimer to acheive a long press touch event.
This might not be an optimal solution, but it worked well for my app.
Here's a snippet of code.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
isAvailable = NO;
timer = [NSTimer scheduledTimerWithTimeInterval:DURATION target:self selector:#selector(didPassTime:) userInfo:nil repeats:NO];
}
- (void)didPassTime:(id)sender{
isAvailable = YES;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
if(isAvailable == YES){
// still pressing after 0.5 seconds
}
else{
// still pressing before 0.5 seconds
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
if(isAvailable == YES){
// releasing a finger after 0.5 seconds
}
else {
// releasing a finger before 0.5 seconds
[timer invalidate];
timer = nil;
}
}