Method 'while' touching screen - ios

I'm making a game using Xcode for iOS. This is a segment of code I have that makes the sprite jump up when the screen is tapped:
//tap/touch to jump (& play sound)
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *) event{
[self playSound];
jumpUp = 16;
}
How can I implement it so that the sprite just keeps going up whist you are touching the screen instead of just a single tap?
//Pseudo code:
while touchingScreen {
jumpUp +=1;
}

You need to start some kind of loop in touchesBegan that runs while the touch is lasting. Then in touchesEnded (and cancelled!) make that loop stop. You can use a repeating NSTimer or something like the following. You may need to do some adjustments to make it smooth enough for a game.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
// touching is a BOOL that keeps track of the touch event
// YES means that a touch is happening at the moment
touching = YES;
dispatch_async(dispatch_get_main_queue(), ^{
[self performSelector:#selector(up) withObject:nil afterDelay:.0];
});
}
- (void)up {
// move your sprite further up
NSLog(#"up");
if (touching) {
// if the user is still touching repeat moving the sprite up
[self performSelector:#selector(up) withObject:nil afterDelay:0.1];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
// The finger was lifted, stop the up movement
touching = NO;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
touching = NO;
}

Related

How to detect a tap gesture using touchesBegan and touchesEnded

I've created a custom control which derives directly from a class UIView. Now I want to perform an action if a user tap on a particular part of my view. So I've overrided methods touchesBegan, touchesEnded and touchesCancelled. The problem is, that the method touchesEnded is never invoked, if I just tap on the display. The method touchesCancelled is called insted of it. touchesEnded is invoked only if I perform some gestures (swipe, move, ...).
Do I need to configure my view anyhow to enable tap gestures?
My code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"touchesBegan");
self->touchDown = YES;
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
self.value = 1.0;
} completion:nil];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (self->touchDown) {
NSLog(#"touchesEnded");
self->touchDown = NO;
[UIView animateWithDuration:0.3 animations:^{
self.value = 0.0;
} completion:nil];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
if (self->touchDown) {
NSLog(#"touchesCancelled");
self->touchDown = NO;
[UIView animateWithDuration:0.3 animations:^{
self.value = 0.5;
} completion:nil];
}
}
For a tap gesture I get:
2018-07-17 09:55:20.994645+0200 iOS Test[33049:2763212] touchesBegan
2018-07-17 09:55:21.092409+0200 iOS Test[33049:2763212] touchesCancelled
Have you tried to set recognizer.cancelsTouchesInView = NO; on your view
A Boolean value affecting whether touches are delivered to a view when a gesture is recognized.
You should go through this.
From Apple documentation,
https://developer.apple.com/documentation/uikit/uigesturerecognizer?changes=_4&language=objc
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Sent to the gesture recognizer when one or more fingers touch down in the associated view.
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//Sent to the gesture recognizer when one or more fingers move in the associated view.
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//Sent to the gesture recognizer when one or more fingers lift from the associated view.
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
//Sent to the gesture recognizer when a system event (such as an incoming phone call) cancels a touch event.
}

Button event when end touch

I want to make voice recorder app. The
recording should start when long touch begins and the
recording must end when user stops the gesture on the button.
UIGestureRecognizer *longGesture=[[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(startrecording)];
How can I handle that when the user leaves the button?
in viewDidLoad method
UILongPressGestureRecognizer *longPressOnButton = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressOnButton:)];
longPressOnButton.delegate = self;
btn.userInteractionEnabled = YES;
[btn addGestureRecognizer:longPressOnButton];
- (void)longPressOnButton:(UILongPressGestureRecognizer*)gesture
{
// When you start touch the button
if (gesture.state == UIGestureRecognizerStateBegan)
{
//start recording
}
// When you stop touch the button
if (gesture.state == UIGestureRecognizerStateEnded)
{
//end recording
}
}
Also you can try or use the touchEvent concept
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)e {
// show touch-began state
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)e {
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)e {
UITouch *touch = [touches anyObject];
.....
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)e {
}
As user3182143 said, using a UILongPressGestureRecorgnizer will solve your problem, but if you are interested there is another way using a UIButton. No need to add a UILongPressGestureRecorgnizer!
From your storyboard, drag an IBAction for a UIButton. And while you are adding its name, change the event to Touch Down.
Now drag another IBAction for the same UIButton and while changing its name, change the event to Touch up Inside (if it isn't that already).
- (IBAction)touchDownButtonAction:(UIButton *)sender {
NSLog(#"Start");
}
- (IBAction)touchUpInsideButtonAction:(UIButton *)sender {
NSLog(#"End");
}
Handle your recording based on the actions!
Here is a screenshot just in case:

Custom UIView: Touch events are not called

This question has been asked many times before and I think I've read most of the threads about it but I still can't find the reason for the behavior in my code.
I create my custom UIView (called BView) programmatically like this:
CGRect frame = [[UIScreen mainScreen] applicationFrame];
_view = [[BView alloc] initWithFrame:frame];
[[[[UIApplication sharedApplication] windows] objectAtIndex:0] addSubview:_view];
When initializing I set UserInteractionEnabled for both the view and the superview to yes and the background color to black, because I've read that some had these problems because their background was transparent:
[self setUserInteractionEnabled:YES];
[self.superview setUserInteractionEnabled:YES];
[self setBackgroundColor:[UIColor blackColor]];
Still the functions to receive touch events are not called:
/* Receive touch events: Touch began */
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
bRenderer::log("Touch began");
[...]
}
/* Receive touch events: Touch moved */
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
bRenderer::log("Touch moved");
[...]
}
/* Receive touch events: Touch ended */
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
bRenderer::log("Touch ended");
[...]
}
Somewhere in my project there is also a view controller that receives touch events without problems and I get no errors anywhere in my project. Yet it is quite important to me to receive the touch events in my view instead of the controller. I really don't get what could be wrong here.
Thank you very much for your help

Forwarding Touches From UIScrollView - UIButton Issues

I have been trying to figure out how to forward the touches from a UIScrollView to its superview. The reason is for sort of a cursor to follow the touch. Anyway, the scrollview is populated with UIButtons. My code for forwarding the touch is to use delegation in a scrollview subclass:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
if ([[self tfDelegate]respondsToSelector:#selector(tfDelegateBegan:)]) {
[[self tfDelegate]tfDelegateBegan:[touches anyObject]];
}
NSLog(#"touches began");
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesMoved:touches withEvent:event];
if ([[self tfDelegate]respondsToSelector:#selector(tfDelegateMoved:)]) {
[[self tfDelegate]tfDelegateMoved:[touches anyObject]];
}
NSLog(#"touches moved");
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesEnded:touches withEvent:event];
if ([[self tfDelegate]respondsToSelector:#selector(tfDelegateEnded:)]) {
[[self tfDelegate]tfDelegateEnded:[touches anyObject]];
}
NSLog(#"touches ended");
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesCancelled:touches withEvent:event];
if ([[self tfDelegate]respondsToSelector:#selector(tfDelegateCancelled:)]) {
[[self tfDelegate]tfDelegateCancelled:[touches anyObject]];
}
NSLog(#"touches cancelled");
}
However, I have learned that UIScrollviews operate via UIGestureRecognizers, so these methods aren't even called by default. I realize that the gesture recognizers are exposed in iOS 5 but I need to support 4.0 as well. I did this instead:
NSArray *a = [[theScrollview gestureRecognizers]retain];
for (UIGestureRecognizer *rec in a) {
if ([rec isKindOfClass:[UIPanGestureRecognizer class]]) {
NSLog(#"this is the pan gesture");
rec.cancelsTouchesInView = NO;
}
}
This allows the gesture to work and the touches methods to be called simultaneously. The issue is, now if you try to scroll while touching a button, the button can be pressed while scrolling. Normally, the scroll cancels the button and the only time a button can be pressed is if the scrollview is not scrolling.
This is the desired functionality. Any suggestions on how I might achieve this?
Maybe try controlling the button action using a flag that would prevent the event from firing if the scroll view is scrolling.
BOOL isScrolling = NO;
- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView {
isScrolling = YES;
}
- (void) scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
isScrolling = NO;
}
- (void) didTapButton {
if(isScrolling)
return;
//Do Button Stuff
}

Detecting Tap & Hold in UITableView cells

How do we detect a tap & hold on a UITableViewCell?
In iOS 3.2 or later you can use UILongPressGestureRecognizer
Here's the code lifted straight from my app. You should add these methods (and a boolean _cancelTouches member) to a class you derive from UITableViewCell.
-(void) tapNHoldFired {
self->_cancelTouches = YES;
// DO WHATEVER YOU LIKE HERE!!!
}
-(void) cancelTapNHold {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(tapNHoldFired) object:nil];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self->_cancelTouches = NO;
[super touchesBegan:touches withEvent:event];
[self performSelector:#selector(tapNHoldFired) withObject:nil afterDelay:.7];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self cancelTapNHold];
if (self->_cancelTouches)
return;
[super touchesEnded:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
[self cancelTapNHold];
[super touchesMoved:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[self cancelTapNHold];
[super touchesCancelled:touches withEvent:event];
}
//Add gesture to a method where the view is being created. In this example long tap is added to tile (a subclass of UIView):
// Add long tap for the main tiles
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longTap:)];
[tile addGestureRecognizer:longPressGesture];
[longPressGesture release];
-(void) longTap:(UILongPressGestureRecognizer *)gestureRecognizer{
NSLog(#"gestureRecognizer= %#",gestureRecognizer);
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan) {
NSLog(#"longTap began");
}
}
You should probably handle the UIControlTouchDown event and depending on what you mean by "hold", fire a NSTimer that will count an interval since you initiated the touch and invalidate upon firing or releasing the touch (UIControlTouchUpInside and UIControlTouchUpOutside events). When the timer fires, you have your "tap & hold" detected.

Resources