I am facing a problem related UITouch. I don't the reason why It's not going with the if case.
Here is the code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if([touch view] == self.transView)
{
NSLog(#"Began");
CGPoint startLocation = [touch locationInView:transView];
startX = startLocation.x;
startY = startLocation.y;
}
}
I am detecting touch on SubView. I added another class's View as subview and this class contains UIImageView on background . For e.g.
UIImageView *BGImageView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"graphBG.png"]];
[BGImageView setContentMode:UIViewContentModeScaleAspectFill];
[BGImageView setFrame:CGRectMake(25, 365, 723, 390)];
[BGImageView setUserInteractionEnabled:YES];
[self.view sendSubviewToBack:BGImageView];
[self.view addSubview:BGImageView];
//[BGImageView release];
myGraph=[[MyGraphControllerView alloc]init];
myGraph.dataForPlot= [[NSMutableArray alloc]init];
for (int i=0; i<[hoursArry count]; i++)
{
NSMutableDictionary *dataDict=[[NSMutableDictionary alloc]init];
[dataDict setObject:[dayArray objectAtIndex:i] forKey:#"x"];
[dataDict setObject:[HoursArray objectAtIndex:i] forKey:#"y"];
[myGraph.dataForPlot addObject:dataDict];
[dataDict release];
}
[myGraph.view setFrame:CGRectMake(25, 380, 723, 390)];
//[myGraph.view setBackgroundColor:[UIColor redColor]];
[self.view addSubview:myGraph.view];
}
I have already added a subview on GraphView but it did not work.
Please help me.
One thing to confirm: Why are you enabling the user interaction on UIImageView??
Set it's intraction disable so that view below it will now be the responder for touches. Kindly update if it doesn't work as i just read your 3 lines of code & you might have some other problem which might be not clear from here.
//add gesture to mapview-for single touch
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(SLideTheView:)];
[touchableView addGestureRecognizer:tap];
tap.numberOfTapsRequired = 1;
I would suggest to go with gesture for the view that needs touch to be detected.
you are checking whether it is touching some view named self.transView
Related
I am trying to programmatically create multiple images then be able to move any of them around the view. I click a button and then I can move that image. I click the button again and I can move that image but no longer can move the first image created. I was trying to use tags.
header.
UIImageView *imageView;
NSUInteger i;
and
#property (nonatomic, retain) UIImageView *imageView;
implementation
#synthesize imageView;
-(IBAction)printTheImage:(id)sender{
UIImageView *theImage = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"animage.png"]];
self.imageView = theImage;
self.imageView.userInteractionEnabled = YES;
self.imageView.frame = CGRectMake(500, 500, 200, 200);
imageView.tag = i;
[self.view addSubview:self.imageView];
i++;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches]anyObject];
CGPoint location = [touch locationInView:self.view];
if ([touch view]==self.imageView)
{
if (ImageView.tag == 1){
self.imageView.center = location;
}
if (imageView.tag == 2){
self.imageView.center = location;
}
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
[self touchesBegan:touches withEvent:event];
}
- (void)viewDidLoad{
i = 1;
[super viewDidLoad];
}
Here's what I came up with from your code
//header
NSUInteger imageCount;
#property (nonatomic, retain) UIImageView *selectedImageView;
//implementation
#synthesize selectedImageView;
-(IBAction)printTheImage:(id)sender {
UIImageView *imageView = [[UIImageView alloc] initWithImage: [UIImage imageNamed: #"animage"]];
[imageView sizeToFit];
imageView.frame = CGRectMake(500, 500, 200, 200);
imageView.userInteractionEnabled = YES;
imageView.tag = imageCount;
[self.view addSubview: imageView];
[imageView release];
imageCount++;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
//iterate trough all images
for (int i = 0; i < imageCount; i++) {
//get image from tag
UIImageView *imageView = (UIImageView *)[self.view viewWithTag: i];
//check which image was tapped
if (CGRectContainsPoint(imageView.frame, [touch locationInView:self.view])) {
NSLog(#"Image #%i was tapped",i);
self.selectedImageView = imageView;
//don't waste processor time for checking all other images, get the first and break the loop
break;
}
}
This is what moves the image:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
//move the tapped image
self.selectedImageView.center = [touch locationInView:self.view];
}
Remeber to reset the image counter and set selectedImageView to nil on touches ended and touches canceled phase
Try this instead.
#property (nonatomic, copy) NSMutableArray *imageViews;
#synthesize imageView;
-(IBAction)printTheImage:(id)sender{
UIImageView *theImage = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"animage.png"]];
[self.imageViews adObject:theImage];
theImage.userInteractionEnabled = YES;
theImage.frame = CGRectMake(500, 500, 200, 200);
imageView.tag = [imageViews indexOfObject:theImage];
[self.view addSubview:theImage];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches]anyObject];
CGPoint location = [touch locationInView:self.view];
NSInteger viewIndex = [self.imageViews indexOfObject:[touch view]];
if (viewIndex != NSNotFound)
UIView *theImage = self.imageViews[viewIndex];
theImage.center = location;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
[self touchesBegan:touches withEvent:event];
}
this approach works with gesture recognizer
#interface ViewController : UIViewController {
int tags;
}
- (IBAction)create:(id)sender;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//Tag to start
tags = 1;
}
- (IBAction)create:(id)sender
{
UIImageView *temp = [[UIImageView alloc] initWithFrame:CGRectMake(0, 100, 200, 200)];
temp.image = [UIImage imageNamed:#"yourimage.jpg"];
temp.userInteractionEnabled = YES;
temp.tag = tags;
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:#selector(handlePan:)];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
tap.numberOfTapsRequired = 1;
[temp addGestureRecognizer:pan];
[temp addGestureRecognizer:tap];
[self.view addSubview:temp];
tags++;
}
//This is just to check if the tags are working
-(void)handleTap:(UITapGestureRecognizer *)recognizer
{
UIView *piece = recognizer.view;
int index = piece.tag;
NSString *msg = [NSString stringWithFormat:#"Tag:%i", index];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Test"
message:msg
delegate:self
cancelButtonTitle:#"ok"
otherButtonTitles:nil, nil];
[alert show];
}
//Drag action
-(void)handlePan:(UIPanGestureRecognizer *)recognizer
{
UIView *piece = recognizer.view;
if ([recognizer state] == UIGestureRecognizerStateBegan || [recognizer state] == UIGestureRecognizerStateChanged)
{
CGPoint translation = [recognizer translationInView:[piece superview]];
[piece setCenter:CGPointMake([piece center].x + translation.x, [piece center].y + translation.y)];
[recognizer setTranslation:CGPointZero inView:[piece superview]];
[self.view bringSubviewToFront:piece];
}
}
#end
already tested and working
good luck
I want to be able to make a gesture recognizer listening for a two finger swipe, anywhere on the screen.
Right now I have a UITableView in a sub-view that scrolls, of course, and it doesn't seem to pick up the UIGestureRecognizer that I set on the view. When you use the two fingers, it just scrolls...
Is there a way to make the entire view, maybe superview, listen for a two finger touch and when it recognizes it, it will instead of scrolling the table view, do what I want it to do?
EDIT: Heres my code but this is suposed to be a very general question. I just want to be able to have UIGestureRecognizers across the entire view, the whole thing.
navBarTitle.title = #"Crunch";
//opening the menuView from launch
//setup the customtable view as a subview in menuView
SDMenuViewController *mvc = [[[SDMenuViewController alloc] initWithNibName:#"SDNestedTableView" bundle:nil] autorelease];
[self addChildViewController:mvc];
[mvc didMoveToParentViewController:self];
[menuView addSubview:mvc.view];
[mvc.view setFrame:CGRectMake(mvc.view.frame.origin.x, mvc.view.frame.origin.y, mvc.view.frame.size.width, mvc.view.frame.size.height + 44)]; //add navBarHeight, for some strage reason
//add swipe down gesture on for the menu
UISwipeGestureRecognizer *swipeClose =[[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(closeMenu)] autorelease];
swipeClose.numberOfTouchesRequired = 2;
swipeClose.direction = UISwipeGestureRecognizerDirectionUp;
UISwipeGestureRecognizer *swipeOpen = [[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(openMenu)] autorelease];
swipeOpen.numberOfTouchesRequired = 2;
swipeOpen.direction = UISwipeGestureRecognizerDirectionDown;
for (UIGestureRecognizer* rec in menuView.gestureRecognizers) {
[rec requireGestureRecognizerToFail:swipeClose];
[rec requireGestureRecognizerToFail:swipeOpen];
}
for (UIGestureRecognizer* rec in mvc.view.gestureRecognizers) {
[rec requireGestureRecognizerToFail:swipeClose];
[rec requireGestureRecognizerToFail:swipeOpen];
}
[mvc.view addGestureRecognizer:swipeClose];
[mvc.view addGestureRecognizer:swipeOpen];
[self.view addGestureRecognizer:swipeClose];
[self.view addGestureRecognizer:swipeOpen];
Maybe I did not explain my question clearly. But for what I was doing this ended up working, and maybe it will help other people in the future:
Two finger swipe in UIScrollview for iPad application
you can try to do something like this:
UISwipeGestureRecognizer* p = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(actionPan:)];
p.numberOfTouchesRequired = 2;
for (UIGestureRecognizer* rec in tableView.gestureRecognizers) {
[rec requireGestureRecognizerToFail:p];
}
[self.view addGestureRecognizer:p];
hope that will help
//In view did load
[self.view setMultipleTouchEnabled:YES];
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([[event touchesForView:self.view] count] > 1) {
NSLog(#"%d active touches",[[event touchesForView:self.view] count]) ;
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeGesture:)];
swipeGesture.direction = UISwipeGestureRecognizerDirectionUp;
[self.view addGestureRecognizer:swipeGesture];
}
}
-(void)handleSwipeGesture:(UISwipeGestureRecognizer *) sender
{
//Gesture detect - swipe up/down , can be recognized direction
if(sender.direction == UISwipeGestureRecognizerDirectionUp)
{
// do some thing...
}
}
i Hope this would solve your problem. and in touches enabled make the count equal to 2 or any number of touches.. :) feel free to ask if you have any doubts
Add another view with frame of self.view over self.view like "viewForGesture" and add gesture recognizer on that view like
UIView *viewForGesture = [[ [UIView alloc]initWithFrame:self.view.frame] autorelease];
[viewForGesture setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:viewForGesture];
.
.
.
[viewForGesture addGestureRecognizer:swipeOpen];
[viewForGesture addGestureRecognizer:swipeClose];
There's two way of making UIView detecting touch. The approach you defined and want that's UIGestureRecognizer, that answer already given by Ezeki.
Another approach you can use to detect touch is to override UITouch delegates.
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if(touch.tapCount==2)
{
//Do something ... (Here, you can also check for the object which touched.)
}
}
I placed 4 UIImageView on UIView and I named them
UIImageView myImg1 = [[UIImageView alloc] init];
UIImageView myImg2 = [[UIImageView alloc] init];
UIImageView myImg3 = [[UIImageView alloc] init];
UIImageView myImg4 = [[UIImageView alloc] init];
How can I tell the compiler that I have just touched down UIImageView 1 or UIImaveView 2. If I only can use UIImageView to do this task, not buttons at all. Please guide me about this issue. Thanks
A stylish solution is to use the UIGestureRecognizer object:
in your loadView method (or anywhere you code the UIImageView(s) drawing...):
UITapGestureRecognizer *tapRecognizer;
UIImageView *anImageView = [[UIImageView alloc] initWithFrame:CGRectMake(20, 20, 100, 100)];
[anImageView setTag:0]; //Pay attention here!, Tag is used to distinguish between your UIImageView on the selector
[anImageView setBackgroundColor:[UIColor redColor]];
[anImageView setUserInteractionEnabled:TRUE];
tapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageViewDidTapped:)] autorelease];
tapRecognizer.numberOfTapsRequired = 1;
[anImageView addGestureRecognizer:tapRecognizer];
[contentView addSubview:anImageView];
[anImageView release];
UIImageView *anotherImageView = [[UIImageView alloc] initWithFrame:CGRectMake(80, 180, 100, 100)];
[anotherImageView setTag:1]; //Pay attention here!, Tag is used to distinguish between your UIImageView on the selector
[anotherImageView setBackgroundColor:[UIColor greenColor]];
[anotherImageView setUserInteractionEnabled:TRUE];
tapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageViewDidTapped:)] autorelease];
tapRecognizer.numberOfTapsRequired = 1;
[anotherImageView addGestureRecognizer:tapRecognizer];
[contentView addSubview:anotherImageView];
[anotherImageView release];
This is a simple imageViewDidTapped: sample method that you can use to distinguish between the two sample UIImageView objects above:
- (void)imageViewDidTapped:(UIGestureRecognizer *)aGesture {
UITapGestureRecognizer *tapGesture = (UITapGestureRecognizer *)aGesture;
UIImageView *tappedImageView = (UIImageView *)[tapGesture view];
switch (tappedImageView.tag) {
case 0:
NSLog(#"UIImageView 1 was tapped");
break;
case 1:
NSLog(#"UIImageView 2 was tapped");
break;
default:
break;
}
}
You should consider using the tag property for this. Give each image a unique tag, then use this information to determine which image was touched. For example, set the tags by
UIImageView myImg1 = [[UIImageView alloc] init];
myImg1.tag = 1;
and when you receive a touch for img, call
img.tag
to retrieve the tag.
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleFingerTap.numberOfTapsRequired = 1;
[myImg1 addGestureRecognizer:singleFingerTap];
[myImg2 addGestureRecognizer:singleFingerTap];
[singleFingerTap release];
And action method
-(void)handleSingleTap:(UIGestureRecognizer*)sender{
//your code here
}
You can do like this.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if(CGRectContainsPoint(myImg1.view.frame,touchLocation))
{
NSLog(#" Image 1");
}
else if(CGRectCont..
Note..the NSLog will be outputted if the point lies in more than one image view..
in that case..check which image view is on top..
- (void)viewDidLoad {
checkingOption = [[UIView alloc] initWithFrame:CGRectMake(45, 250, 17, 15)];
checkingOption.backgroundColor = [UIColor grayColor];
checkingOption.layer.cornerRadius = 5;
checkingOption.layer.masksToBounds = YES;
checkingOption.opaque = NO;
[self.view addSubview:checkingOption];
[checkingOption setUserInteractionEnabled:YES];
}
That is my new on main view.now i want to test that is user touching on that or not...
-(void)touchesBegan: (NSSet *)touches withEvent:(UIEvent *)event{
[self.usernameField resignFirstResponder];
[self.passwordField resignFirstResponder];
UITouch *touch =[touches anyObject];
CGPoint startPoint =[touch locationInView:checkingOption];
if(CGRectContainsPoint(checkingOption.frame,startPoint)){
NSLog(#"touch inside the checking view");
}
Please help me..i am not finding the problem.
Thanks in Advance.
add UITapGestureRecognizer to your view
UITapGestureRecognizer *singleTapOne = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleTapOne.numberOfTouchesRequired = 1; singleTapOne.numberOfTapsRequired = 1; singleTapOne.delegate = self;
[self.view addGestureRecognizer:singleTapOne]; [singleTapOne release];
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer
{
}
Hola guys.
I'm experiencing a little problem with touch handling and UIResponder.
My goal is to manage a single touch (moved) to interact with different views.
I added a gesture recognizer to my UIImageView that send a simple message to my customViewController. It allocate and display a custom view (subclassing a UIButton) over the tapped UIImageView.
I would be able (without have to release the initial finger tap) to send touch movement to my new allocated custom button.
It seems that my UIImageView swallow my touch and so my new Button can't feel the finger movement.
I tried to resign first responder but it seems having no effect.
My custom Button work pretty good but only if I release the first tap and then tap again over the new displayer button.
Any suggests?
Thank you in advance.
Some code here:
Inside my viewController I attached a longPressGestureRecognizer to my profileImageView that draw a circular button surrounding the profileImageView.
-(void)showMenu:(UIGestureRecognizer*)gesture {
[profileImageView removeGestureRecognizer:gesture];
[profileImageView setUserInteractionEnabled:NO];
ConcentricRadius radius;
radius.externalRadius = 75;
radius.internalRadius = 45;
GTCircularButton *circularMenu = [[[GTCircularButton alloc] initWithImage:[UIImage imageNamed:#"radio.png"] highlightedImage:[UIImage imageNamed:#"radio_selected.png"] radius:radius] autorelease];
[circularMenu setTag:kCircularTagControllerCircularMenu];
[circularMenu setCenter:[profileImageView center]];
// Buttons' frames will be set up by the circularMenu
UIButton *button1 = [[[UIButton alloc] init] autorelease];
UIButton *button2 = [[[UIButton alloc] init] autorelease];
UIButton *button3 = [[[UIButton alloc] init] autorelease];
UIButton *button4 = [[[UIButton alloc] init] autorelease];
[circularMenu setButtons:[NSArray arrayWithObjects:button1, button2, button3, button4, nil]];
//[[self view] addSubview:circularMenu];
[[self view] insertSubview:circularMenu belowSubview:profileImageView];
}
Now I handle manually the touchEvent inside the circularMenu using the touchMoved methods.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchLocation = [(UITouch*)[touches anyObject] locationInView:self];
for (UIView *aSubview in _roundButtons) {
if ([aSubview isKindOfClass:[UIButton class]]) {
UIButton *aButton = (UIButton*)aSubview;
CGPoint buttonTouchPointConverted = [aButton convertPoint:touchLocation toView:aButton];
if (CGRectContainsPoint([[aButton layer] frame], buttonTouchPointConverted)) {
[self rotateHighlightImage:aButton];
}
}
}
}
The goal is always to handle the end of gestureRecognizer and pass the touch event to the new instance created without having to lift my finger from the screen.
Any ideas?
PD: I handle touch manually with touchMoved cause if I use the addTarget:action:forControlEvents: on my buttons (1,2,3, and 4) the button that detect touchEvent swallow it and make other buttons impossible to feel the touch moving over them.
Your touchesEnded:withEvent: will have to be the same as your touchesMoved:withEvent: except it must invoke the method which is probably tied to the control event Touch Up Inside event.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchLocation = [(UITouch*)[touches anyObject] locationInView:self];
for (UIView *aSubview in _roundButtons) {
if ([aSubview isKindOfClass:[UIButton class]]) {
UIButton *aButton = (UIButton*)aSubview;
CGPoint buttonTouchPointConverted = [aButton convertPoint:touchLocation toView:aButton];
if (CGRectContainsPoint([[aButton layer] frame], buttonTouchPointConverted)) {
[aButton sendActionsForControlEvents:UIControlEventTouchUpInside];
return;
}
}
}
}
The only change I have made is to have the button send that control event for us.
Original Answer
In the function that handles your gesture, do this,
if ( gesture.state == UIGestureRecognizerStateEnded ) {
CGPoint point = [gesture locationInView:button];
if ( CGRectContainsPoint(button.bounds, point) ) {
[button sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
This checks whether the last touch of the gesture was inside the button and sends a touch up inside event to all its targets.
Ok guys finally I solved my problem and I reached my goal!!
I discovered what was the real problem.
Simply the GestureRecognizer handle touch Event until it's state is setted to UIGestureRecognizerStateEnded and for this reason the GestureRecognizer swallow touch events with no opportunity to send touch events to the rest of responder chain.
I read again the UIGestureRecognizer class reference and I found the property enabled.
To solve my problem the first thing I do when the gesture launch the target method is to set the gesture enabled to NO. In this way the gesture release immediately the touch control and the touchMoved can be executed.
Hope this help someone.
Above the modified code:
-(void)showMenu:(UIGestureRecognizer*)gesture {
[gesture setEnabled:NO]; // This is the key line of my problem!!
[profileImageView removeGestureRecognizer:gesture];
[profileImageView setUserInteractionEnabled:NO];
ConcentricRadius radius;
radius.externalRadius = 75;
radius.internalRadius = 45;
GTCircularButton *circularMenu = [[[GTCircularButton alloc] initWithImage:[UIImage imageNamed:#"radio.png"] highlightedImage:[UIImage imageNamed:#"radio_selected.png"] radius:radius] autorelease];
[circularMenu setTag:kCircularTagControllerCircularMenu];
[circularMenu setCenter:[profileImageView center]];
// Buttons' frames will be set up by the circularMenu
UIButton *button1 = [[[UIButton alloc] init] autorelease];
UIButton *button2 = [[[UIButton alloc] init] autorelease];
UIButton *button3 = [[[UIButton alloc] init] autorelease];
UIButton *button4 = [[[UIButton alloc] init] autorelease];
[circularMenu setButtons:[NSArray arrayWithObjects:button1, button2, button3, button4, nil]];
//[[self view] addSubview:circularMenu];
[[self view] insertSubview:circularMenu belowSubview:profileImageView];
}
I think you should change a setting on the view, once you create the button. Eg.
myImageView.userInteractionEnabled = NO;
This way, the UIImageView will not listen to the touches any more.
Let me know if it works.