I have a great problem since last 2 days. I'm working with a multiple Touch enabled view. My UIViewController has 8-10 imageview. I want to detect touch on each view separately, but multiple view at a time. Touch is detected on all image view, but problem is here-
Suppose I have Tap on a image view and hold down this image view and now tap another image view, second image view is detected touch successfully but it also trigger to first image view which is previously touched and hold down. But I don't want it. So please any one help me. Code level help is appreciated.
NB. My UIViewController also implemented TouchesMoved Methods for swiping purpose.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for(UITouch *touch in event.allTouches) {
if(CGRectContainsPoint([imView1 frame], [touch locationInView:self.view])){
NSLog(#"imView 1 touched");
}
if(CGRectContainsPoint([imView2 frame], [touch locationInView:self.view])){
NSLog(#"imView 2 touched");
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for(UITouch *touch in event.allTouches) {
if(CGRectContainsPoint([imView1 frame], [touch locationInView:self.view])){
NSLog(#"imView 1 touch moved");
}
if(CGRectContainsPoint([imView2 frame], [touch locationInView:self.view])){
NSLog(#"imView 2 touch moved");
}
}
}
Try subclassing a UIImageView and handle the touches code in that subclass. If you need to pass the touch to the parent for some reason, you can handle the touch then send it on to the parent which would be your view controller.
EDIT:
have your custom class like this
#interface CustomImageView : UIImageView {}#end
#implementation CustomImageView
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"touch began %d",self.tag);
[self.nextResponder touchesBegan:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"touch moved %d",self.tag);
[self.nextResponder touchesMoved:touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"touch ended %d",self.tag);
[self.nextResponder touchesEnded:touches withEvent:event];
}
#end
and have your parrent code something like this
#implementation trashmeTouchIpadViewController
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"parent Touch Began");
//do parent stuff
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"parent Touch ended");
//do parent stuff
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setMultipleTouchEnabled:YES];
UIImage *i1 = [UIImage imageNamed:#"img1.jpg"];
CustomImageView *v1 = [[CustomImageView alloc] initWithImage:i1];
v1.frame = CGRectMake(100, 100, 200, 200);
v1.userInteractionEnabled = YES;
v1.multipleTouchEnabled = YES;
v1.tag = 111;
[self.view addSubview:v1];
[v1 release];
UIImage *i2 = [UIImage imageNamed:#"img2.jpg"];
CustomImageView *v2 = [[CustomImageView alloc] initWithImage:i2];
v2.frame = CGRectMake(500, 100, 200, 200);
v2.userInteractionEnabled = YES;
v2.multipleTouchEnabled = YES;
v2.tag = 999;
[self.view addSubview:v2];
[v2 release];
}
Related
I have an image inside of a UIScrollView and I have code which draws text as the user drags their finger around. I'd like to be able to control, when the user is touching the screen, if
a) the user should be using their finger to draw OR
b) the user should be moving the scroll view around with their finger
I have a boolean which keeps track of what the user is doing. And I have touches methods:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
if(draw == false) {
printf("calling super");
[scrollView touchesBegan:touches withEvent:event];
}
else
[myPath moveToPoint:[mytouch locationInView:self]];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
if(draw == false)
[scrollView touchesMoved:touches withEvent:event];
else {
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
Why doesn't this work? Basically, if I'm not drawing, I call the touchesBegan and touchesMoved of the scroll view. If I am drawing, I draw using myPath.
However, the scroll view is not moved around or zoomed in, etc, as it should be, when draw is false.
i have met this problem before. And i solve like this:
you should make a mainView . It has 2 property. One is yourScrollView , and One is yourDrawImageView. [yourScrollView addSubviews:yourDrawImageView];[mainView addSubviews:yourScrollView];
and then write your touches method in the mainView.m like this (ignor the scrollView statment)
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
if ([[touches allObjects] isKindOfClass:[yourDrawImageView class]])
{
[myPath moveToPoint:[mytouch locationInView:self]];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
if ([[touches allObjects] isKindOfClass:[yourDrawImageView class]])
{
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
}
The last step , whats you ignor is to code scrollView touches event , its write in yourSceollView.m,like this:
#import "yourScrollView.h"
#implementation yourScrollView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
if(!self.dragging)
[[self nextResponder] touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesMoved:touches withEvent:event];
if(!self.dragging)
[[self nextResponder] touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesEnded:touches withEvent:event];
if(!self.dragging)
[[self nextResponder] touchesEnded:touches withEvent:event];
}
- (void)dealloc {
[super dealloc];
}
#end
I wish it can help you :-)
UIScrollView uses UIGestureRecognizers, which are called by the system separately from touchesBegan:withEvent: and friends. An easier way to do this is to simply disable scrolling on the scroll view when you don't want it to react to touches.
I have an application in which i have to move images, problem is arising when mouse touches the images it gets moved but if it touches the main View, whole view is also moving.
I tried view.userInteractionEnabled=NO;
but after one move whole view gets freeze.
I want my view to be static(not moving)
Help !!!
here is the code
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
UIImageView *imgPimples = [[UIImageView alloc]init];
imgPimples = (UIImageView*)[touch view];
CGPoint touchLocation = [touch locationInView:imgPimples];
imgPimples.center = touchLocation;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
Just check whether touched class is of kind UIImageView.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
if ([[touch view] isKindOfClass:[UIImageView class]]) {
UIImageView *imgPimple;
imgPimple = (UIImageView *)[touch view];
CGPoint touchLocation = [touch locationInView:imgPimple];
imgPimple.center = touchLocation;
}
}
I think it will serve your purpose.
if ([touch.view isKindOfClass:[UIImageView class]]){
imgPimples.center = touchLocation;
}
assuming your parent view is not also a UIImageView.
I'm trying to create an overlay view that monitors for touches and then disappears, but also forwards touch events to whatever is underneath the view.
My test app has a view with a button inside. I add the overlay view as another subview (sibling to the button, essentially), which takes up the entire screen.
For both solutions I tried, the overlay keeps state to determine how it responds to a touch. When a touchesBegan event is received, the overlay will stop responding to hitTest or pointInside until it receives a touchesCancelled or touchesEnded.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if(_respondToTouch)
{
NSLog(#"Responding to hit test");
return [super hitTest:point withEvent:event];
}
NSLog(#"Ignoring hit test");
return nil;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
if(_respondToTouch)
{
NSLog(#"Responding to point inside");
return [super pointInside:point withEvent:event];
}
NSLog(#"Ignoring point inside");
return NO;
}
For my first approach, I tried re-issuing the event:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if(!_respondToTouch)
{
NSLog(#"Ignoring touches began");
return;
}
NSLog(#"Responding to touches began");
_respondToTouch = NO;
[[UIApplication sharedApplication] sendEvent:event];
}
- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touches cancelled");
_respondToTouch = YES;
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touches ended");
_respondToTouch = YES;
}
However, the button didn't respond to the re-issued event.
My second approach was to use hitTest to discover the view (my button) underneath the overlay, and then send a touchesXXX message directly to it:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touches began");
_respondToTouch = NO;
UITouch* touch = [touches anyObject];
_touchDelegate = [[UIApplication sharedApplication].keyWindow hitTest:[touch locationInView:self.superview] withEvent:event];
CGPoint locationInView = [touch locationInView:_touchDelegate];
NSLog(#"Sending touch %# to view %#. location in view = %f, %f", touch, _touchDelegate, locationInView.x, locationInView.y);
[_touchDelegate touchesBegan:touches withEvent:event];
}
- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touches cancelled");
[_touchDelegate touchesCancelled:touches withEvent:event];
_respondToTouch = YES;
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touches ended");
[_touchDelegate touchesEnded:touches withEvent:event];
_respondToTouch = YES;
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touches moved");
[_touchDelegate touchesMoved:touches withEvent:event];
}
It finds the button (according to the logs), but the button doesn't react at all when I invoke touchesXXX on it.
I'm not sure what else to try since the button won't respond to a direct invocation of touchesBegan =/
This is a beginner's question I'm afraid:
I have an UIText which covers the entire screen. I have another transparent view on top of this UITextView so as to be able to recognise swiping gestures (horizontally and vertically), like so:
- (void)viewDidLoad
{
[super viewDidLoad];
// UITextView
CGRect aFrame = CGRectMake(0, 0, 320, 480);
aTextView = [[UITextView alloc] initWithFrame:aFrame];
aTextView.text = #"Some sample text.";
[self.view addSubview:aTextView];
// canTouchMe
CGRect canTouchMeFrame = CGRectMake(0, 0, 320, 480);
canTouchMe = [[UIView alloc] initWithFrame:canTouchMeFrame];
[self.view addSubview:canTouchMe];
}
Let's consider the user touches (not swipes) the canTouchMe View. In this case, I would like the canTouchMe view to disappear and pass on the touch to the UITextView hiding beneath so that it enters the editing mode and enable the 'natural' scrolling options an UITextView has (i.e. only horizontally).
My touches began method looks like this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UITouch *touch =[touches anyObject];
gestureStartPoint = [touch locationInView:self.view];
}
How do I tell this method that IF it recognises only ONE touch, that it should hide the canTouchMeFrame and PASS ON the touch to the UITextView?
Sorry if this is basic, but I have no idea how to implement this. Thanks for any suggestions.
EDIT:
I introduced a touchEnded method, but I still have no luck. The touch will not be forwarded to the UITextView. I need to tap twice in order to edit it:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesMoved:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView:self.view];
CGFloat deltaX = fabsf(gestureStartPoint.x - currentPosition.x); // will always be positive
CGFloat deltaY = fabsf(gestureStartPoint.y - currentPosition.y); // will always be positive
if (deltaY == 0 && deltaX == 0) {
label.text = #"Touch"; [self performSelector:#selector(eraseText) withObject:nil afterDelay:2];
[aTextView touchesBegan:touches withEvent:event];
[self.view bringSubviewToFront:aTextView];
[self.view bringSubviewToFront:doneEdit];
}
}
NSSet has a -count method. If touches only has one object, then you're responding to a single touch.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
if ([touches count] == 1) {
[self hideMyRectangle];
[someOtherObject touchesBegan:touches withEvent:event];
//etc, etc.
return;
}
// if you get here, there's more than one touch.
UITouch *touch =[touches anyObject];
gestureStartPoint = [touch locationInView:self.view];
}
I have an UIViewController which contains a UITableView (subclassed) and another UIView (subclassed). They are on the same hierarchy level but the UIView is added last so it is the frontmost.
I overrid touchesBegan/Moved/Ended to intercept the Gestures from the top UIView: my goal is to get the selected UITableViewCell and, if double tapped, create an ImageView to be dragged around.
I appear to get it done but now I cannot scroll the UITableView anymore, even though I forward the touch events.
Here are the methods for the UIView:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"BO");
UITouch * touch = [touches anyObject];
CGPoint tPoint = [touch locationInView:self];
InventoryViewController * invViewCont = self.viewController;
UITableView * invTab = invViewCont.inventoryTableView;
[invTab deselectRowAtIndexPath:[invTab indexPathForSelectedRow]
animated:YES];
NSArray * cells = [invTab visibleCells];
BOOL found = NO;
for (UITableViewCell * cell in cells)
{
if (CGRectContainsPoint(cell.frame, tPoint))
{
[cell touchesBegan:touches withEvent:event];
found = YES;
break;
}
}
if (!found)
{
[invViewCont.inventoryTableView touchesBegan:touches withEvent:event];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"Mo");
UITouch * touch = [touches anyObject];
CGPoint tPoint = [touch locationInView:self];
copyObj.center = tPoint;
InventoryViewController * invViewCont = self.viewController;
UITableView * invTab = invViewCont.inventoryTableView;
[invTab deselectRowAtIndexPath:[invTab indexPathForSelectedRow]
animated:YES];
NSArray * cells = [invTab visibleCells];
BOOL found = NO;
for (UITableViewCell * cell in cells)
{
if (CGRectContainsPoint(cell.frame, tPoint))
{
[cell touchesMoved:touches withEvent:event];
found = YES;
break;
}
}
if (!found)
{
[invViewCont.inventoryTableView touchesMoved:touches withEvent:event];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch * touch = [touches anyObject];
if ([touch tapCount] == 2)
{
[self desubCopyView];
}
CGPoint tPoint = [touch locationInView:self];
copyObj.center = tPoint;
InventoryViewController * invViewCont = self.viewController;
UITableView * invTab = invViewCont.inventoryTableView;
[invTab deselectRowAtIndexPath:[invTab indexPathForSelectedRow]
animated:YES];
NSArray * cells = [invTab visibleCells];
BOOL found = NO;
for (UITableViewCell * cell in cells)
{
if (CGRectContainsPoint(cell.frame, tPoint))
{
[cell touchesEnded:touches withEvent:event];
//[cell.imageView touchesEnded:touches withEvent:event];
found = YES;
break;
}
}
if (!found)
{
[invViewCont.inventoryTableView touchesEnded:touches withEvent:event];
}
}
And here are those in the UITableViewCell
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch * touch = [touches anyObject];
if ([touch tapCount] == 2)
{
CGPoint tPoint = [touch locationInView:self];
NSLog(#"CellX %lf CY %lf", tPoint.x, tPoint.y);
UIGraphicsBeginImageContext(self.bounds.size);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView * newView = [[UIImageView alloc] initWithImage:viewImage];
[dragArea addSubview:newView];
dragArea.copyObj = newView;
[newView release];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.4];
dragArea.copyObj.transform = CGAffineTransformMakeScale(1.3, 1.3);
[UIView commitAnimations];
tPoint = [self convertPoint:tPoint toView:dragArea];
dragArea.copyObj.center = tPoint;
}
[super touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"MOV %#", self.imageView.image);
[super touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"ENDED");
[super touchesEnded:touches withEvent:event];
}
And in my UITableView I have simply:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"BEGTB");
[super touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"MOVTB");
[super touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"ENDTB");
[super touchesEnded:touches withEvent:event];
}
I am surely missing something but I do not know what
I would highly recommend looking into UITapGestureRecognizer instead of handling the touchesX events yourself.
I found a workaround for this, override the methods for touch gestures in my custom UITableView in order to make it scroll programMatically as I drag upon it an object.
Here is the 'solution'.
I still believe there is another simpler way to do this but I did not find it, so posting this and marking it as an 'answer' might help someone else.