I want to move UIImageView by tappig the location on the screen. How do I get X, Y coordinates of the tapping finger?
in the viewDidLoad.m, this could do the job :
/* Create the Tap Gesture Recognizer */
self.tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTaps:)];
/* The number of fingers that must be on the screen */
self.tapGestureRecognizer.numberOfTouchesRequired = 1;
/* The total number of taps to be performed before the gesture is recognized */
self.tapGestureRecognizer.numberOfTapsRequired = 1;
/* Add this gesture recognizer to our view */
[self.view addGestureRecognizer:self.tapGestureRecognizer];
And then in the handleTaps: method
- (void) handleTaps:(UITapGestureRecognizer*)paramSender{
NSUInteger touchCounter = 0;
for (touchCounter = 0; touchCounter < paramSender.numberOfTouchesRequired; touchCounter++)
{
CGPoint touchPoint = [paramSender locationOfTouch:touchCounter inView:paramSender.view];
NSLog(#"Touch #%lu: %#", (unsigned long)touchCounter+1, NSStringFromCGPoint(touchPoint));
}
}
Of course, you implement the handleTaps method regarding your needs.
You can use any of below methods
If you want it to be moved on touched begin Event, use this
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event{}
If you want it to be moved on touches ended event, use this
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{}
and place the code pasted below
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint pt = [[touches anyObject] locationInView:self.view];
imageView.center = CGPointMake(pt.x,pt.y);
}
In Above code , the pt Contains the x and y co-ordinates of your touched location.
Moreover you may also use animations for smoother moves.
Related
I am super frustrated and I know it is just because I don't know what i am doing with cocos2d. I am following Ray Wenderlich tutorials on cocos2d and I am trying to put it all together. When the screen is tapped,one bullet is fired in the direction of the tap. I am using
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
[self.officer shootToward:touchLocation];
[self.officer shootNow];
}
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
[self.officer shootToward:touchLocation];
[self.officer shootNow];
}
which calls these methods in my Officer class
- (void)shootNow {
// 1
CGFloat angle = ccpToAngle(_shootVector);
_gun.rotation = (-1 * CC_RADIANS_TO_DEGREES(angle)) + 90;
// 2
CGSize winSize = [[CCDirector sharedDirector] winSize];
float mapMax = MAX(winSize.width, winSize.height);
CGPoint actualVector = ccpMult(_shootVector, mapMax);
// 3
float POINTS_PER_SECOND = 300;
float duration = mapMax / POINTS_PER_SECOND;
// 5
for(id item in self.children) {
NSString *bulletName = [NSString stringWithFormat:#"bullet.png"];
CCSprite * bullet = [CCSprite spriteWithSpriteFrameName:bulletName];
//bullet.tag = _type;
bullet.position = ccpAdd(self.position, ccpMult(_shootVector, _gun.contentSize.height));
CCMoveBy * move = [CCMoveBy actionWithDuration:duration position:actualVector];
CCCallBlockN * call = [CCCallBlockN actionWithBlock:^(CCNode *node) {
[node removeFromParentAndCleanup:YES];
}];
[bullet runAction:[CCSequence actions:move, call, nil]];
[self.batchNode addChild:bullet];
//[self addChild:bullet];
[_shotsFired addObject:bullet];
}
}
So I figured it would be a simple for loop go through the 5th step x amount of times then call a reload method. Well that didn't work. So I tried to count the touches on the screen, I figured if I got x amount of taps then call the reload method(which is not written yet)? The problem with that was every time you pressed a different area of the screen the count started over from one. Some please help me through this week long process of pulling my hair out? How do I count the amount of times I have fired the gun?
Couldn't you just make a property on your view controller and then every time the shoot now method is called just add 1 to your property, then reset it to 0 when you call the reload method?
I have a simple full screen UIView . When the user taps on the screen, I need write out the x,y
Console.WriteLine ("{0},{1}",x,y);
What API Do i need to use for that?
In MonoTouch (since you asked in C#...although the previous answer is correct :) that would be:
public override void TouchesBegan (NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
var touch = touches.AnyObject as UITouch;
if (touch != null) {
PointF pt = touch.LocationInView (this.View);
// ...
}
You could also use a UITapGestureRecognizer:
var tapRecognizer = new UITapGestureRecognizer ();
tapRecognizer.AddTarget(() => {
PointF pt = tapRecognizer.LocationInView (this.View);
// ...
});
tapRecognizer.NumberOfTapsRequired = 1;
tapRecognizer.NumberOfTouchesRequired = 1;
someView.AddGestureRecognizer(tapRecognizer);
Gesture recognizers are nice as they encapsulate touches into reusable classes.
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
printf("Touch at %f , %f \n" , [touch locationInView:self.view].x, [touch locationInView:self.view].y);
}
how to remove subviews very fast according to user touched point or moving point in the view.I am able to get the user touched point and moved point in the view and also i can remove the subview according with the user touched point using [subview removefromsuperview];.
When the user moves very fast some subviews getting deleted and some of the images not getting deleted.If the user moves slowly then subviews getting deleted exactly.i am placing some of my code is below
`
-(void)deleteSubView:(CGPoint)userCurrentPoint{
for(int i=0;i<[subviews count];i++){
if (CGRectContainsPoint([[subviews objectAtIndex:i] CGRectValue], userCurrentPoint)) {
[[superview viewWithTag:i ] removeFromSuperview];
}
}
`
is there any way to delete subviews according with the user fast moving points.i need your suggestion.
Thanks all
Put this in your header file:
#interface YourView : UIView
#property (nonatomic, assign) CGPoint lastTouchLocation;
#end
This should be the implementation:
#implementation YourView
#synthesize lastTouchLocation;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
self.lastTouchLocation = [[touches anyObject] locationInView:self];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
CGPoint oldLocation = self.lastTouchLocation;
CGPoint newLocation = [[touches anyObject] locationInView:self];
for (UIView *subview in self.subviews)
{
if (LineIntersectsRect(oldLocation, newLocation, subview.frame))
{
[subview removeFromSuperview];
}
}
self.lastTouchLocation = newLocation;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
self.lastTouchLocation = CGPointZero;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
self.lastTouchLocation = CGPointZero;
}
#end
What this does: we check whether or not a line between the last received touch and the current one intersects the frame of a subview. Why? See deanWombourne's answer.
Here's the intersection code, originally by habjan - you should put in in the header, too.
static inline BOOL LineIntersectsLine(CGPoint l1p1, CGPoint l1p2, CGPoint l2p1, CGPoint l2p2)
{
CGFloat q = (l1p1.y - l2p1.y) * (l2p2.x - l2p1.x) - (l1p1.x - l2p1.x) * (l2p2.y - l2p1.y);
CGFloat d = (l1p2.x - l1p1.x) * (l2p2.y - l2p1.y) - (l1p2.y - l1p1.y) * (l2p2.x - l2p1.x);
if(d == 0)
{
return false;
}
CGFloat r = (q / d);
q = (l1p1.y - l2p1.y) * (l1p2.x - l1p1.x) - (l1p1.x - l2p1.x) * (l1p2.y - l1p1.y);
CGFloat s = (q / d);
if((r < 0) || (r > 1) || (s < 0) || (s > 1))
{
return false;
}
else
{
return true;
}
}
static inline BOOL LineIntersectsRect(CGPoint p1, CGPoint p2, CGRect r)
{
if (CGRectContainsPoint(r, p1) || CGRectContainsPoint(r, p2))
{
return YES;
}
else
{
CGPoint topLeft = CGPointMake(r.origin.x, r.origin.y);
CGPoint topRight = CGPointMake(r.origin.x + r.size.width, r.origin.y);
CGPoint bottomLeft = CGPointMake(r.origin.x, r.origin.y + r.size.height);
CGPoint bottomRight = CGPointMake(r.origin.x + r.size.width, r.origin.y + r.size.height);
return (LineIntersectsLine(p1, p2, topLeft, topRight) ||
LineIntersectsLine(p1, p2, topRight, bottomRight) ||
LineIntersectsLine(p1, p2, bottomRight, bottomLeft) ||
LineIntersectsLine(p1, p2, bottomLeft, topLeft));
}
}
It's not to do with your enumeration :)
If the user moves their finger quickly, you don't get a list of every pixel they touched, you get some of them. If they were to move fast enough, you might only get the start and end points.
You can't just use the point that their finger is dragged to, you have to work out which subviews have been touched between the last event and this one :)
Think of it as drawing a line between the start and end points and working out which subviews overlap with that line.
If I understand your question correctly, you want to remove all the subviews that the user touches as he drags his finger across your view.
Your problem is that touchesMoved:withEvent: fires at a limited frequency. It isn't guaranteed to fire for every pixel the user touches. As a result, when the user moves his finger quickly, there are gaps between the points reported in touchesMoved:withEvent. If the user moves his finger quickly enough, these gaps may be large enough that they skip over some subviews entirely.
To solve this problem your code needs to remember the position of the previous point, and then test the line segment formed by the previous point and the current point to see if it intersects with the frame of the subview. An efficient algorithm for this is described in: How to test if a line segment intersects an axis-aligned rectange in 2D?
I have a view control and inside I plan to place some controls like buttons textbox etc... I can drag my view along the x axis like:
1)
2)
with the following code:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
if( [touch view] == ViewMain)
{
CGPoint location = [touch locationInView:self.view];
displaceX = location.x - ViewMain.center.x;
displaceY = ViewMain.center.y;
startPosX = location.x - displaceX;
}
CurrentTime = [[NSDate date] timeIntervalSince1970];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
if( [touch view] == ViewMain)
{
CGPoint location = [touch locationInView:self.view];
location.x =location.x - displaceX;
location.y = displaceY;
ViewMain.center = location;
}
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
double time = [[NSDate date] timeIntervalSince1970]-CurrentTime;
UITouch *touch = [[event allTouches] anyObject];
if( [touch view] == ViewMain)
{
CGPoint location = [touch locationInView:self.view];
location.x =location.x - displaceX;
location.y = displaceY;
ViewMain.center = location;
double speed = (ViewMain.center.x-startPosX)/(time*2);
NSLog(#"speed: %f", speed);
}
}
not that I have to add the global variables:
float displaceX = 0;
float displaceY = 0;
float startPosX = 0;
float startPosY = 0;
double CurrentTime;
the reason why I created those variables is so that when I start dragging the view the view moves from the point where I touch it instead of from the middle.
Anyways if I touch a button or image the view will not drag even though the images have transparency on the background. I want to be able to still be able to drag the view regardless if there is an image on top of the view. I where thinking that maybe I need to place a large transparent view on top of everything but I need to have buttons, images etc. I want to be able to drag a view just like you can with:
note that I was able to drag the view regardless of wither I first touched an app/image or text. How could I do that?
I think your problem is that if you touch a UIButton or a UIImageView with interaction enabled, it doesn't pass the touch along.
For the images, uncheck the User Interaction Enabledproperty in IB.
For the buttons that are causing touchesBegan:withEvent:, etc. to not get called, then look at the following link: Is there a way to pass touches through on the iPhone?.
You may want to consider a different approach to this problem. Rather than trying to manually manage the content scrolling yourself you would probably be better off using a UIScrollView with the pagingEnabled property set to YES. This is the method Apple recommends (and it's probably the method used by Springboard.app in your last screenshot). If you are a member of the iOS developer program check out the WWDC 2010 session on UIScrollView for an example of this. I think they may have also posted sample code on developer.apple.com.
I am trying to detect double taps on a view, but when the double tap comes, the first tap triggers an action on TouchesBegan, so, before detecting a double tap a single tap is always detected first.
How can I make this in a way that just detects the double tap?
I cannot use OS 3.x gestures, because I have to make it compatible with old OS versions.
thanks
Some excerpts from the tapZoom example of the scrollViewSuite sample code:
First, the function to kick off things once the touch ended:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 1) {
[self performSelector: #selector(handleSingleTap)
withObject: nil
afterDelay: 0.35]; // after 0.35s we call it a single tap
} else if([touch tapCount] == 2) {
[self handleDoubleTap];
}
}
Second: intercept the message if a new touch occurs during timeout:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[NSObject cancelPreviousPerformRequestsWithTarget: self
selector: #selector(handleSingleTap)
object: nil];
}
see also: http://developer.apple.com/iphone/library/documentation/WindowsViews/Conceptual/UIScrollView_pg/ZoomingByTouch/ZoomingByTouch.html#//apple_ref/doc/uid/TP40008179-CH4-SW1
and here: (scrollView suite)
http://developer.apple.com/iphone/library/samplecode/ScrollViewSuite/Introduction/Intro.html
Edit: I missed the point that you said you cannot use 3.x gestures, so this is an invalid answer to your question, but I'm leaving it in case someone who can use 3.x gestures may benefit from it.
You can create two gesture recognizers, one for single tap and one for double tap:
UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTouchesOne:)];
singleTapGesture.cancelsTouchesInView = NO;
singleTapGesture.delaysTouchesEnded = NO;
singleTapGesture.numberOfTouchesRequired = 1; // One finger single tap
singleTapGesture.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:singleTapGesture];
[singleTapGesture release];
UITapGestureRecognizer *doubleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTouchesTwo:)];
doubleTapGesture.cancelsTouchesInView = NO;
doubleTapGesture.delaysTouchesEnded = NO;
doubleTapGesture.numberOfTouchesRequired = 1; // One finger double tap
doubleTapGesture.numberOfTapsRequired = 2;
[self.view addGestureRecognizer:doubleTapGesture];
[doubleTapGesture release];
And then, here comes the punch:
[singleTapGesture requireGestureRecognizerToFail : doubleTapGesture];
The last line, makes your single tap handler work only if the double tap fails. So, you get both single tap and double tap in your application.
Are you looking at the tapCount? For example:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
if (touch.tapCount == 2) {
//double-tap action here
}
}