UIScrollview getting touch events - objective-c

How can I detect touch points in my UIScrollView? The touches delegate methods are not working.

Set up a tap gesture recognizer:
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[scrollView addGestureRecognizer:singleTap];
and you will get the touches in:
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
CGPoint touchPoint=[gesture locationInView:scrollView];
}

You can make your own UIScrollview subclass and then you can implement the following:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"DEBUG: Touches began" );
UITouch *touch = [[event allTouches] anyObject];
[super touchesBegan:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"DEBUG: Touches cancelled");
// Will be called if something happens - like the phone rings
UITouch *touch = [[event allTouches] anyObject];
[super touchesCancelled:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"DEBUG: Touches moved" );
UITouch *touch = [[event allTouches] anyObject];
[super touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"DEBUG: Touches ending" );
//Get all the touches.
NSSet *allTouches = [event allTouches];
//Number of touches on the screen
switch ([allTouches count])
{
case 1:
{
//Get the first touch.
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
switch([touch tapCount])
{
case 1://Single tap
break;
case 2://Double tap.
break;
}
}
break;
}
[super touchesEnded:touches withEvent:event];
}

If we're talking about the points inside the scrollview then you can hook with the delegate method:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
and inside the method, read the property:
#property(nonatomic) CGPoint contentOffset
from the scrollView to get the coordination.

This works also on touch down event.
In the currently as correct marked answer you can get a touch point only at a "Tap" event. This event seems only to fire on "finger up" not on down.
From the comment of yuf in the same answer you can get the touch point from the underlying view also within the UIScrollView.
- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldReceiveTouch:(UITouch*)touch
{
CGPoint touchPoint = [touch locationInView:self.view];
return TRUE; // since we're only interested in the touchPoint
}
According to Apple's documentation the gestureRecognizer does:
Ask the delegate if a gesture recognizer should receive an object representing a touch.
which means to me that I can decide if a gestureRecognizer should recieve a touch or not.

Related

UIView detecting touches in only one half of the screen

I am currently working on a 3D OpenGLES-based iPhone Game project and I want to have a view that detect touches so I can then rotate my camera according to the touch gestures.
So here I created a TouchPad class that derives from UIView to record the touch gestures.
Once done I have figured out that only half of the screen is effective. The whole left side.
Whenever i touch the right part of the screen it does not call the -[touchesBegan] method
Here is my class definition
#interface TouchPad : UIView
{
CGPoint fingerMove, originalPosition;
}
#property (nonatomic, assign) CGPoint fingerMove;
#end
And here is my class implementation
#import "TouchPad.h"
#implementation TouchPad
#synthesize fingerMove;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
fingerMove = CGPointMake(0, 0);
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
std::cout << "called";
UITouch *touch = [touches anyObject];
originalPosition = [touch locationInView:self];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView:self];
fingerMove = CGPointMake(currentPosition.x - originalPosition.x,
currentPosition.y - originalPosition.y);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
{
UITouch *touch = [touches anyObject];
originalPosition = [touch locationInView:self];
fingerMove = CGPointMake(0, 0);
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
fingerMove = CGPointMake(0, 0);
}
#end
And here is how i use it inside my ViewController
- (void)prepareGame
{
game = [[MainGame alloc] init];
[self.view addSubview:game.IrrView];
[game.IrrView release];
rotationPad = [[TouchPad alloc] initWithFrame:CGRectMake(0.0, 0.0,
[[UIScreen mainScreen] bounds].size.width,
[[UIScreen mainScreen] bounds].size.height)];
[self.view addSubview:rotationPad];
[rotationPad release];
}
- (void)runGame
{
[game updateMapPattern];
[game updateCamera :rotationPad.fingerMove];
[game draw];
}
I really want to know how to make the touchPad work in the whole screen and not only the left part of the screen. Maybe there is a conflict with my game view

Xcode object moving towards finger im new here

Hi guys I am preety new here.
And I have a UIimageview.
And I know what is the coordinates of a UITouch.
Now I want the ball(UIImageView) to go towards it.
I tried to think of ways to do this...
Using CGPoint
But I cant think on any way that will work properly
How can I do that? (i didnt found answer in the internet)
- (void)viewDidLoad
{
[super viewDidLoad];
[self play];
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(play) userInfo:nil repeats:YES];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
ballvelocity = [touch locationInView:self.view];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
ballvelocity = [touch locationInView:self.view];
}
-(void) play{
[UIView animateWithDuration:3 animations:^{
ball.center = CGPointMake(ballvelocity.x, ballvelocity.y);
}];
}
if you are good with block..
you can create a animation with
UIView animateWithDuration:(NSTimeInterval) animations:^(void)>
other wise
UIView beginAnimations:(NSString *) context:(void *)
in both the animation methods you can set
[imageView setCenter:yourlocation];
this will animate it to the position.
more info on animating views here :
https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/doc/uid/TP40006816

Get original touch location from UIPanGestureRecognizer

My view has a UIPanGestureRecognizer added to it.
The problem is that by the time the touch is recognized as a pan gesture, it has to be moved a few points, and I can't extract the original touch location at the UIGestureRecognizerStateBegan state.
In this state the translationInView: is (0,0), and any subsequent moves are calculated from this point, and not from the original.
Is there a way to extract the original location from the gesture recognizer itself, or do I need to override the touchesBegan: method?
You should be able to set the delegate for the gesture recogniser and implement
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
to get the initial touch.
You can solve this problem by implementing a custom PanGestureRecognizer which saves the original touch point and makes it available to the caller.
I went this route as I also wanted to control the distance moved to trigger a pan gesture.
This might be overkill for your situation, but works perfectly and is less difficult than it sounds.
To get the touchpoint coordinates, you just call:
[sender touchPointInView:yourView]
instead of:
[sender locationInView:yourView]
Here's the code for PanGestureRecognizer.m:
#import "PanGestureRecognizer.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
#implementation PanGestureRecognizer
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
// touchPoint is defined as: #property (assign,nonatomic) CGPoint touchPoint;
self.touchPoint = [touch locationInView:nil];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:nil];
// customize the pan distance threshold
CGFloat dx = fabs(p.x-self.touchPoint.x);
CGFloat dy = fabs(p.y-self.touchPoint.y);
if ( dx > 2 || dy > 2) {
if (self.state == UIGestureRecognizerStatePossible) {
[self setState:UIGestureRecognizerStateBegan];
}
else {
[self setState:UIGestureRecognizerStateChanged];
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
if (self.state == UIGestureRecognizerStateChanged) {
[self setState:UIGestureRecognizerStateEnded];
}
else {
[self setState:UIGestureRecognizerStateCancelled];
}
}
- (void) reset
{
}
// this returns the original touch point
- (CGPoint) touchPointInView:(UIView *)view
{
CGPoint p = [view convertPoint:self.touchPoint fromView:nil];
return p;
}
#end
If you use locationInView: rather than translationInView: you will get absolute coordinates instead of relative coordinates. However you do have to start the pan to get input... To work around this your view can be a UIButton and you can trigger a - (IBAction)buttonWasTouched:(UIButton *)button forEvent:(UIEvent *)event connected to "touch down" like so:
-(IBAction)shakeIntensityPanGesturebuttonWasTouched:(UIButton *)button forEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view]; //touch location local cordinates
}
You can use the UIGestureRecognizerState
- (void) onPanGesture:(UIPanGestureRecognizer *)sender {
if(sender.state == UIGestureRecognizerStateBegan) {
origin = [sender locationInView];
} else {
current = [sender locationInView];
// Initial touch stored in origin
}
}
Swift (ish):
var state = recognizer.state
if state == UIGestureRecognizerState.Began {
println(recognizer.locationInView(viewForGesture))
//this will be the point of first touch
}

how to let the touchesMoved only control one view?

i create an UIButton on the view,and i want to let the touchesMoved only control the UIButton,not the whole view
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint touchMoved = [touch locationInView:self.view];
}
i want to do like this
if i touch the UIButton,and then the UIButton can be moved with my finger,if i touch other view and my finger is moving on the screen,the UIButton does nothing.
that means the function touchesMoved only has the role of the UIButton,so how can i do it? thanks
I presume the code you show takes place in your custom view controller subclass, and the UIButton is a subview of its view.
Define a simple BOOL in your class that you set to NO first. Then update it in the event handling methods.
// .h
BOOL buttonTouched;
// .m
// in the viewDidLoad
buttonTouched = NO;
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// test wether the button is touched
UITouch *touch = [touches anyObject];
CGPoint touchBegan = [touch locationInView:self.view];
if(CGRectContainsPoint(theButton.frame, touchBegan) {
buttonTouched = YES;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if(buttonTouched) {
// do it here
UITouch *touch = [touches anyObject];
CGPoint touchMoved = [touch locationInView:self.view];
CGRect newFrame = CGRectMake(touchMoved.x,
touchMoved.y,
theButton.frame.width,
theButton.frame.height);
theButton.frame = newFrame;
}
}
// when the event ends, put the BOOL back to NO
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
buttonTouched = NO;
}

Avoid UIView touch delay

I am using a subclass of UIView in my app. When the user touches on view I need to get the coordinates of the point; for this I am using:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
currentPoint=[[touches anyObject]locationInView:self];
}
It has some delay. Can any one give me the solution to get the points immediately? Thank you all.
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
self.frame=frame;
rect=[[NSMutableArray alloc] initWithCapacity:1];
currentPointsList=[[NSMutableArray alloc]initWithCapacity:1];
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
firstTouchedPoint = [touch locationInView:self];
NSLog(#"the firstTouched point is %");
for (int i=0; i<[rect count]; i++) {
if(CGRectContainsPoint([[rect objectAtIndex:i]CGRectValue], firstTouchedPoint)){
CGRect firstLineRect = CGRectMake(firstTouchedPoint.x,
[[rect objectAtIndex:i]CGRectValue].origin.y,
[[rect objectAtIndex:i]CGRectValue].size.width-firstTouchedPoint.x+[[rect objectAtIndex:i]CGRectValue].origin.x,
[[rect objectAtIndex:i]CGRectValue].size.height);
UIImageView *firstLine=[[UIImageView alloc]initWithFrame:firstLineRect];
firstLine.backgroundColor=[[UIColor blueColor]colorWithAlphaComponent:0.3f];
[self addSubview:firstLine];
break;
}
}
If you are using a UIScrollView there is a delay touches property (delaysContentTouches). You may want to make sure that is NO.