i am developing a card game which requires uiimageviews. i have a view based application. i have added 5imageviews in it.
each imageview has a unique card. nw the user can drag a card on top of any other card present. for this i need to know which card has been selected. how to do this?
touches enabled works in all places in my view. i want touches to be enabled only on uiimageview.
how can i activate touches to the imageviews alone present in my viewcontroller.
thanks in advance..
What you can do is in touchesBegan: method you can check which location in your view is selected using
CGPoint point = [recognizer locationInView:self];
And then do a for loop to check which imageview is selected like this
for(i = 0; i < 5; i++)
{
if(CGRectContainsPoint(imageView.frame, point))
{
// do something.
}
}
UITouch *touch = [touches anyObject];
CGPoint offSetPoint = [touch locationInView:myImageView];
Now u have defined only the myImageView object to receive the touches. Write these lines the touchesBegan or touchesEnded method as u require... Hope this helps....Dont forget to set the userInteractionEnabled property of the imageview to YES for the touches to work.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint pnt = [[touches anyObject]locationInView:self.view];
UIImageView *imgView;
if((pnt.x > CGRectGetMinX(imgView.frame) && pnt.x < CGRectGetMaxX(imgView.frame))&&
(pnt.y > CGRectGetMinY(imgView.frame) && pnt.y < CGRectGetMaxY(imgView.frame)) &&
ChkOfferCount==TRUE)
{
UIAlertView *obj = [[UIAlertView alloc]initWithTitle:#"Image Touched"
message:#"Selected image is this" delegate:nil
cancelButtonTitle:#"cancel"
otherButtonTitles:#"ok",nil];
[obj show];
[obj release];
}
}
Set imageView.userInteractionEnabled=YES; and you can work with the touches methods on the imageView itself e.g. touchesBegan: You can work with these methods to handle the drag and drop of the cards.
You can also create UIControl view then fill it entirely with UIImageView then simply catch touch events in UIControl.
Related
I know there are lots of questions on multi finger touches and restrictions here and there,but none of them seem to work.All they suggest is to try setting exclusive touch and disable multi touch i.e.:
[self.view.subviews makeObjectsPerformSelector:#selector(setExclusiveTouch:) withObject:[NSNumber numberWithBool:YES]];
[self.view setMultipleTouchEnabled:NO];
Note: Initially when I used self.view.exclusiveTouch = NO; ,it didn't work for me.Mr.Hlung's comment in the 1st link provided some useful info of enabling the subviews exclusive touch through selector.
But they seem to work incomplete.I have a game view where there are multiple images on left and their corresponding images on the right.User has to drag the left image to the respective right image and match it.I am using UIPanGestureRecognizer to do so.Here comes a scenario which was the outcome of some rash testing by a tester in my office :)
When the user scrambles the images,i.e. plays awkwardly with all/few of his fingers,what happens is the frames are getting disturbed or few images overlap with one another.This is all because some where multiple touch is still available for user.Hence I want to eliminate that feature.I am also aware of the fact that there is a method called -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event ,through which we can detect the number of user touches.What if I delete all user touches if the count is more than 1,i.e. if more than 1 finger touch is detected!!!
But I found no method to remove touches there,I also tried to assign last touch object to my image view through which I thought would ignore the rest of touches detected,i.e.:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([event allTouches].count>1)
{
UITouch *touch = [[touches allObjects] lastObject];
self.dragObjectImageView = (UIImageView *)[touch view];
}
}
Even this doesn't seem to work.
EDIT-Setting Max and Min number of touches:
I have also set the pan gesture's max and min no of touches to 1 as well,i.e.:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view.subviews makeObjectsPerformSelector:#selector(setExclusiveTouch:) withObject:[NSNumber numberWithBool:YES]];
for(UIImageView *iView in self.movableArray){
if ([iView isMemberOfClass:[UIImageView class]]){
UIPanGestureRecognizer * recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
recognizer.minimumNumberOfTouches = 1;
recognizer.maximumNumberOfTouches = 1;
iView.multipleTouchEnabled = NO;
[iView addGestureRecognizer:recognizer];
[iView setUserInteractionEnabled:YES];
recognizer.delegate = self;
}
}
}
Tried another tactic of disabling user interaction for image if multiple touches are detected,but in vain!
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([event allTouches].count > 1)
{
for (UIView* view in self.view.subviews)
{
if ([view isKindOfClass:[UIImageView class]])
{
[view setUserInteractionEnabled:NO];
}
}
}
else
{
for (UIView* view in self.view.subviews)
{
if ([view isKindOfClass:[UIImageView class]])
{
[view setUserInteractionEnabled:YES];
}
}
}
}
Some people might say there can't be a case where user will use multiple fingers to play.But I was asked to fix the issue and a developer has to obey and respect the testers perspective as well.
Can some one please help me get rid of the problem.
Thanks every one in advance :)
Instead of setting exclusive touch to our own view,turning on the same for the subview or the view we assign to self.view worked,in my case it is...
[gameView.subviews makeObjectsPerformSelector:#selector(setExclusiveTouch:) withObject:[NSNumber numberWithBool:YES]];
Hope it helps some one,thanks :)
As per apple documentation for the property multipleTouchEnabled in UIView Class Reference
multipleTouchEnabled
Other views in the same window can still receive touch events when
this property is NO. If you want this view to handle multi-touch
events exclusively, set the values of both this property and the
exclusiveTouch property to YES.
I see in your code, you've set setExclusiveTouch to all subviews but setMultipleTouchEnabled only for the container view and not all image views. Add the following line before/after setting exclusive touch and single touch may work correctly.
[self.view.subviews makeObjectsPerformSelector:#selector(setMultipleTouchEnabled:) withObject:[NSNumber numberWithBool:NO]];
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.
How can I make it so that while the user is playing on the joystick to move the character at the centre they can also touch the bottom right of the screen (the second touch) to fire the gun? I have looked at other questions but I still cant figure it out...
this is basically the code....:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//make the touch point...
UITouch *touch = [[event allTouches]anyObject];
CGPoint point = [touch locationInView:touch.view];
if (//touching a certain area (on the joystick)) {
//do stuff
}
else if (point.x > 300 && point.y > 200) {
/fire method
}
}
so basically how do I call touchesBegan again to find the position of CGPoint point, and work out if the fire method should be called?
Thanks
EDIT:
I have tried to do that 2nd option and done this:
in view controller.h I added:
#interface fireView: UIView
#end
and in .m I added:
#implementation fireView -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"hi");
}
#end
....but it doesn't log/print "hi"?
Use 2 UIGestureRecognizers. You can create 2 invisible views of needed size - one for joystick and one for fire button. For every view use single gesture recognizer. And then you will be able to handle taps on these view by in different methods without checking if it was fire or joystick.
Let's think you have 2 views - joystickView and fireView already. Then do it like
UITapGestureRecognizer* fireTapGestureRec= [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(fireTapped:)];
fireTapGestureRec.delegate = self;
fireTapGestureRec.numberOfTapsRequired = 1;
fireTapGestureRec.numberOfTouchesRequired = 1;
[fireView addGestureRecognizer:fireTapGestureRec];
[fireTapGestureRec release];
and write fireTapped: to handle the event. And the same thing for joystick.
EDIT
Second option (suggested in comments)
Make subclasses of UIView, like
#interface fireView: UIView
#interface joystickView: UIView
and for each subclass write it own touchesBegan: or touchesEnded:
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);
}
How would I go about adding gesture events to uipickerview to change tabs? I have to create a custom class, however, I don't know how to handle the uipickerview. I current have gestures present in uiviews to do this, but I'm having trouble with the uipickerview.
My code for the views:
#define HORIZ_SWIPE_DRAG_MIN 100
CGPoint mystartTouchPosition;
BOOL isProcessingListMove;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint newTouchPosition = [touch locationInView:self.view];
if(mystartTouchPosition.x != newTouchPosition.x || mystartTouchPosition.y != newTouchPosition.y) {
isProcessingListMove = NO;
}
mystartTouchPosition = [touch locationInView:self.view];
[super touchesBegan:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = touches.anyObject;
CGPoint currentTouchPosition = [touch locationInView:self.view];
// If the swipe tracks correctly.
double diffx = mystartTouchPosition.x - currentTouchPosition.x + 0.1; // adding 0.1 to avoid division by zero
double diffy = mystartTouchPosition.y - currentTouchPosition.y + 0.1; // adding 0.1 to avoid division by zero
if(abs(diffx / diffy) > 2.5 && abs(diffx) > HORIZ_SWIPE_DRAG_MIN)
{
// It appears to be a swipe.
if(isProcessingListMove) {
// ignore move, we're currently processing the swipe
return;
}
if (mystartTouchPosition.x < currentTouchPosition.x) {
isProcessingListMove = YES;
self.tabBarController.selectedViewController = [self.tabBarController.viewControllers objectAtIndex:0];
return;
}
else {
isProcessingListMove = YES;
self.tabBarController.selectedViewController = [self.tabBarController.viewControllers objectAtIndex:2];
return;
}
}
else if(abs(diffy / diffx) > 1)
{
isProcessingListMove = YES;
[super touchesMoved:touches withEvent:event];
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
isProcessingListMove = NO;
[super touchesEnded:touches withEvent:event];
}
Thanks for the help.
You CAN subclass UIPickerView. The problem is that it's comprised of nine subviews, one of which, called UIPickerTable, is receiving the touch events like touchesBegan:withEvent: to the rows you want. I was able to successfully intercept these with the code included at the end of this post:
Responding to touchesBegan in UIPickerView instead of UIView
The other answers/comments there are helpful too. I wanted to clear the air, not for someone doing something non-standard (as in this question), but for someone who arrived here wishing to subclass UIPickerView, because the first line of the accepted answer is dead wrong.
You can't subclass UIPickerView.
However, since a picker view must be displayed in another view (since it doesn't take up the entire screen) you can trap the touches in that view's controller and filter for gestures.
(Assuming I understand what your trying to do...) I would warn that swiping a picker view to change tabs is a non-standard UI and will probably confuse your users. Since a picker view is perceived as a type of control, they will expect only the normal spinning action of the picker. How would they even know to swipe a picker view horizontally?
I left it alone. It would have been confusing, you're right.
ZT> You can't subclass UIPickerView.
"In order to make the picker view spin longer, I subclassed UIPickerView. My subclass had exactly one method" from Longer Spinning and Blurring. Also see UIPickerView Class Reference: "The UIDatePicker class uses a custom subclass of UIPickerView to display dates and times."