This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
UIScrollview getting touch events
Is it possible to detect where in a UIScrollView the finger touched?
I mean, suppose the user uses his finger in this way: taps and scroll, lifts the finger and again, taps and scroll, etc. Is it possible to know the CGPoint where the taps happened in relation to the self.view the scroller is in? The scroller occupies the whole self.view.
Thanks.
You can do it with gesture recognizers. For detect single tap location use UITapGestureRecognizer
UITapGestureRecognizer *tapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapAction:)] autorelease];
[myScrollView addGestureRecognizer:tapRecognizer];
- (void)tapAction:(UITapGestureRecognizer*)sender{
CGPoint tapPoint = [sender locationInView:myScrollView];
CGPoint tapPointInView = [myScrollView convertPoint:tapPoint toView:self.view];
}
To convert that tapPoint to self.view you can use convertPoint:toView: method in UIView class
Take a look at touchesBegan:withEvent: You will get a NSSet of UITouch's, and a UITouch contains a locationInView: method that should return the CGPoint of the touch.
You'd probably be able to subclass it and look at touchesBegan.
http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIResponder_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006783-CH4-SW1
You could find the location in the view and add the scroll ofset to it. Now, your next problem is that -(void)touchesBegan:touches:event won't be called because the events will be sent to your scrollview. This can be fixed by subclassing your UIScrollView and have the scrollview send the touch events to the next responder (your view).
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Position of touch in view
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
// Scroll view offset
CGPoint offset = scrollView.contentOffset;
// Result
CGPoint scrollViewPoint = CGPointMake(touchPoint.x, touchPoint.y + offset.y);
NSLog(#"Touch position in scroll view: %f %f", scrollViewPoint.x, scrollViewPoint.y);
}
Related
I have a UIButton in my project and after a button click I am showing a UIView on the top of that button in such a way that the button remains hidden that time. I want to get a touchesmoved event on that time when I keep that button pressed and move finger over the overlapped UIView. As far as I did is like the following:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if ([touch view] == uiview)
{
NSLog(#"Touches moved");
}
but it doesnt get called when I keep the button pressed that is hidden when the UIView comes up and the uiview goes hidden when I release the button. Any suggestion please?
I don't quiet understand what your trying to do but I would suggest you use UIGestureRecognizers and add Gestures Recognizers to your button.
Try using this code. I've used this in a card game i developed. moving cards around using long press gestures. Hope i helps.
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(addLongpressGesture:)];
[longPress setDelegate:self];
[YOUR_BUTTON addGestureRecognizer:longPress];
- (void)addLongpressGesture:(UILongPressGestureRecognizer *)sender {
UIView *view = sender.view;
CGPoint point = [sender locationInView:view.superview];
if (sender.state == UIGestureRecognizerStateBegan){
// GESTURE STATE BEGAN
}
else if (sender.state == UIGestureRecognizerStateChanged){
//GESTURE STATE CHANGED/ MOVED
CGPoint center = view.center;
center.x += point.x - _priorPoint.x;
center.y += point.y - _priorPoint.y;
view.center = center;
// This is how i drag my views
}
else if (sender.state == UIGestureRecognizerStateEnded){
//GESTURE ENDED
}
You need to set view.userInteractionEnabled = NO for your overlapped UIView.
This will send action to button.
I have an image view. i detected touch in image view like this
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
int viewTag=[touch view].tag;
if ([[touch view] isKindOfClass:[UIImageView class]])
{
//My code
}
}
and touches moved on image view. whenever my touch moved out off the image view in that particular time i need one alert view. how to detect that touch over from the image view in touches moving?...
I recommend using a UIPanGestureRecognizer and adding it to a larger super-view of the image-view you want to detect on. That way even if the touch starts outside and moves into and out of your image-view you can follow the movement of the touch in your gesture handler.
It's pretty easy, make a method called handlePan: for example, create the gesture recognizer using your handler method, add it to the appropriate super-view. Now whenever the gesture is active and the touch moves your handler method will get called and you can check to see if it is inside your image view.
You should use this method...
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
int viewTag=[touch view].tag;
if ([[touch view] isKindOfClass:[UIImageView class]])
{
//My code
}
else
{
//show the alertView here
}
}
and to check that the initial click was on the imageView you have to set a flag in the touchesBegan method... and check it accordingly in the touchesMoved method
You may add a transparent UIButton of the same size on top of the UIImageViewand track UIControlEventTouchDragOutside
[button addTarget:self action:#selector(draggedOutside:) forControlEvents:UIControlEventTouchDragExit];
I currently am using a UIScrollView to work as a way of scrolling/ dragging the cursor/ marker of a graph that I am displaying on my app. I use scrollViewDidScroll, etc. to detect the contentoffset's position and manipulate what I display on the screen based on this position.
My question is if it is possible to also detect a user's single tap on the screen and get this tap's position (to then set the contentoffset to this position)?
I have read some tutorials that describe creating a subclass of a uiscrollview, but it seems like these subclasses will ONLY account for a single tap and not drags/scrolls also.
Does anyone have any insight on how I might be able to detect a user's single tap on my UIScrollView while still having its scrolling/ dragging capabilities?
Thank you in advance!
Use the following code for your scrollView object :
UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTap:)];
singleTapGestureRecognizer.numberOfTapsRequired = 1;
singleTapGestureRecognizer.enabled = YES;
singleTapGestureRecognizer.cancelsTouchesInView = NO;
[scrollView addGestureRecognizer:singleTapGestureRecognizer];
//[singleTapGestureRecognizer release]; Not needed in ARC-enabled Project
}
- (void)singleTap:(UITapGestureRecognizer *)gesture {
//handle taps
}
Swift 5
let scrollViewTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(scrollViewTapped(_:)))
scrollViewTapGestureRecognizer.numberOfTapsRequired = 1
scrollViewTapGestureRecognizer.isEnabled = true
scrollViewTapGestureRecognizer.cancelsTouchesInView = false
scrollView.addGestureRecognizer(scrollViewTapGestureRecognizer)
#objc func scrollViewTapped(_ sender: UITapGestureRecognizer) {
print("UIScrollView was tapped.")
}
The first part of the question is pretty simple to get going. If you have a UIScrollView subclass, you can just add a touchesEnded override that looks like this:
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 1) {
CGPoint location = [touch locationInView:self];
[self setContentOffset:location animated:YES];
}
}
In the case of the scroll view, the -locationInView for the touch will actually already have the ContentOffset added into it. What this code will do is scroll the scroll view so that the point the user touched is at the top-left of the view. This probably isn't what you want exactly, so you'll have to do things like add in an offset if you want the scroll to end up 10 pixels in, or you'd make another CGPoint with only the x value out of the location if your scroller isn't left-to-right.
This won't interfere with being able to actually do the scroll.
Have you looked into attaching UITapGestureRecognizer to the scrollView? I've attached a UITapGestureRecognizer to a UIScrollView and used –gestureRecognizerShouldBegin: and/or –gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: to cancel the built in panning when a touch is desired.
I am facing below problem:-
Please have a look in the below image the thing what i want is:-
I want to drag default images from view 1 to view 2 and images have to be always thr in view1 so its not like touch moved to draging images .
i tried a lot things in that but i succeed in draging image from one view to another but in view2 i am not able to get touch points so its just adding thr as frame
But i cnt able to touch tht image across view2 and even in view2
i want to do other functionality like zooming and others but first want to get touch points in view2.
I am giving description image about this problem.
The edited question is:-
i have done this simple demo in this i am transferring one view to another view and after getting view2 points its been in its limit boundaries.
but how can i get the default things remain in their.
i will modify this code i will add images in this view. but its just shows my thinking here so guide me here.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if ([touch view] == view3) {
CGPoint location = [touch locationInView:self.view];
view3.center = location;
return;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
int tmpValue = 0;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
{
onceDone = TRUE;
if(onceDone == TRUE)
{
UITouch *touch = [touches anyObject];
CGPoint pt = [touch locationInView:self.view];
NSLog(#"X = %f y=%f",pt.x,pt.y);
view3.center = pt;
if(view3.frame.origin.x < view2.frame.origin.x )
//view3.frame.origin.x < view2.frame.origin.x)
[view3 setFrame:CGRectMake(159,view3.frame.origin.y, view3.frame.size.width, view3.frame.size.height)];
}
}
[UIView commitAnimations];
}
Please help me.
it is urgent.
Thanks in advance
If you are using pan gestures are touchesMoved method to drag and drop the images.Make super view of view1 and view2 to same UIView and calculate your gesture location or touched point with respect to that common super view.That means your view1 and view2 will be on the same view and each subView(image)is also added to main view only.So you can move images on main view where ever you want and can perform any operation on them.
We have been working in a similar issue, and we have made up with this solution:
We have an UIPanGestureRecognizer added to each button.
When we detect the pan gesture begin, we create the object we want to drag (in this case, it could be a copy of your image). You should have to set a rect equals to the button, or if you create the object in a different view, you should have to convert the object coordinates so the object seems in the same position as the button, but inside his view.
After that we move the last created object, instead of move the button.
And that is, the trick here is the UIPanGestureRecognizer works until you untouch the screen, but it is triggered while you move your finger for all the screen, not only inside the button!
I hope this works for you.
I have some nested views like this:
First, there is an big UIView. Inside this, there is another UIView. And inside this, there is an MyNiceButtons class that inherits from UIView. So I have:
UIView > UIView > MyNiceButtons (= an UIView).
In detail, the UIView creates an UIImageView and adds it as a child view to itself, which represents an graphical button. So inside the MyNiceButtons class implementation, I have this code to handle a touch event on the fake button image:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject]; // i just need single touches
// just to see which view is affected
UIView *tview = [touch view];
CGRect rect = tview.frame;
rect.origin.x = rect.origin.x + 20.0f;
tview.frame = rect;
[tview setBackgroundColor:[UIColor yellowColor]];
if ([touch view] == self.fakeButtonImageView) {
NSLog(#"touch on fake button detected");
}
}
All views in the hierarchy have userInteractionEnabled=YES. The touch arrives at the first view in the hierarchy (the parent of the parent).
UIView *tview = [touch view];
This returns just the parent of the parent, but not the UIImageView where the user actually tapped on.
What's the trick to recognize if the touch was on the button UIImageView?
I would first suggest that you take a good look at what you can do with a Custom-type UIButton (can set images for various states). 95% of the time, this should address your needs.
If you have some other need, I can help you debug w/ hitTest, etc.