Identify specific image view from multiple imageviews - objective-c

I have a single image view, and I set other image views on it and put them in different locations. I want to apply FLIP ANIMATION on mage view. How can do it? when if(i==1) then my imageview is flipped. img1 is my image view and I want to identify it. I allocate 52 images in `imagearr
My code:
-(void)setCards
{
int k=0;
CGFloat dx = self.view.frame.size.width/2;
CGFloat dy = self.view.frame.size.height/2;
int cnt = [imagearr count];
for (int j=1; j<3; j++) // Number of cards
{
for (int i=1; i<5; i++) // Number of players
{
int rnd = (arc4random() % cnt)-1;
UIImage *img = [imagearr objectAtIndex:rnd];
UIImageView *img1 = [[UIImageView alloc] initWithImage:img];
CGRect frame = img1.frame;
frame.size.width = frameX;
frame.size.height = frameY;
[img1 setFrame:frame];
[img1 setTag:k+i];
[UIView beginAnimations:#"Move" context:nil];
[UIView setAnimationDuration:0.50];
if (i==1)
{
[img1 setCenter:CGPointMake(dx+100, dy+(j*15))];
}
if (i==2)
{
[img1 setCenter:CGPointMake(dx+(j*15), dy+60)];
}
if (i==3)
{
[img1 setCenter:CGPointMake(dx-130, dy-(j*15))];
}
if (i==4)
{
[img1 setCenter:CGPointMake(dx-(j*20), dy-95)];
}
[self.view addSubview:img1];
[UIView commitAnimations];
[img1 release];
}
k=k+10;
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
int t = [touch view].tag;
}
I still can't identify a specific imageview. Please help me to solve this problem.

Setting tag for individual imageView is the best approach. Using tag you could even detect multiples images placed inside tableview cells and set action for selection of individual tag as well.

I think you should take a look at the Apple sample project GeekGameBoard. It implements a solitaire game and you will be able to learn how to select CALayers* representing cards, drag them around, and have them interact with each other.
*Which will be both easier and probably better from a performance perspective than using views.

Associate a unique tag values with each UIImageView instances.
Code for reference.
myImageView1.tag = 1;
myImageView1.tag = 2;
myImageView1.tag = 3;

Apple Link For the code:
Detect imageview from multiple imageview
Stack Link As Well
Here is the discussion for to detect the images from the multiple images
Good Luck

There will be different images in different imageView so each imageView will be on different position.
in your touch method do you have to check the bounds of the touch and then you have to match which imageView lies under your touch region.According to that you can proceed your functionality.

You can probably place a invisible UIbutton over your imageviews and capture touch event. The effect is the same and its much more cleaner and simpler. Let me know if you need more info. Would be happy to edit my answer here.

you could try something similar to this
-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event //here enable the touch
{
// get touch event
UITouch *touch = [[event allTouches] anyObject];
int t = [touch view].tag;
UIImageView *imageView = (UIImageView *) [self.view viewWithTag:t];
//your logic here
}

Related

How do I detect a touch event on a moving UIImageView?

When researching "How do I detect a touch event on a moving UIImageView?" I've come across several answers and I tried to implement them to my app. Nothing I've come across seems to work. I'll explain what I'm trying to do then post my code. Any thoughts, suggestions, comments or answers are appreciated!
My app has several cards floating across the screen from left to right. These cards are various colors and the object of the game is the drag the cards down to their similarly colored corresponding container. If the user doesn't touch and drag the cards fast enough, the cards will simply drift off the screen and points will be lost. The more cards contained in the correct containers, the better the score.
I've written code using core animation to have my cards float from the left to right. This works. However when attempting to touch a card and drag it toward it's container, it isn't correctly detecting that I'm touching the UIImageView of the card.
To test if my I'm properly implementing the code to move a card, I've also written some code allows movement for a non-moving card. In this case my touch is being detected and acting accordingly.
Why can I only interact with stationary cards? After researching this quite a bit it seems that the code:
options:UIViewAnimationOptionAllowUserInteraction
is the key ingredient to get my moving UIImages to be detected. However I tried this doesn't seem to have any effect.
I another key thing that I may be doing wrong is not properly utilizing the correct presentation layer. I've added code like this to my project and I also only works on non-moving objects:
UITouch *t = [touches anyObject];
UIView *myTouchedView = [t view];
CGPoint thePoint = [t locationInView:self.view];
if([_card.layer.presentationLayer hitTest:thePoint])
{
NSLog(#"You touched a Card!");
}
else{
NSLog(#"backgound touched");
}
After trying these types of things I'm getting stuck. Here is my code to understand this a bit more completely:
#import "RBViewController.h"
#import <QuartzCore/QuartzCore.h>
#interface RBViewController ()
#property (nonatomic, strong) UIImageView *card;
#end
#implementation RBViewController
- (void)viewDidLoad
{
srand(time (NULL)); // will be used for random colors, drift speeds, and locations of cards
[super viewDidLoad];
[self setOutFirstCardSet]; // this sends out 4 floating cards across the screen
// the following creates a non-moving image that I can move.
_card = [[UIImageView alloc] initWithFrame:CGRectMake(400,400,100,100)];
_card.image = [UIImage imageNamed:#"goodguyPINK.png"];
_card.userInteractionEnabled = YES;
[self.view addSubview:_card];
}
the following method sends out cards from a random location on the left side of the screen and uses core animation to drift the card across the screen. Notice the color of the card and the speed of the drift will be randomly generated as well.
-(void) setOutFirstCardSet
{
for(int i=1; i < 5; i++) // sends out 4 shapes
{
CGRect cardFramei;
int startingLocation = rand() % 325;
CGRect cardOrigini = CGRectMake(-100,startingLocation + 37, 92, 87);
cardFramei.size = CGSizeMake(92, 87);
CGPoint origini;
origini.y = startingLocation + 37;
origini.x = 1200;
cardFramei.origin = origini;
_card.userInteractionEnabled = YES;
_card = [[UIImageView alloc] initWithFrame:cardOrigini];
int randomColor = rand() % 7;
if(randomColor == 0)
{
_card.image = [UIImage imageNamed:#"goodguy.png"];
}
else if (randomColor == 1)
{
_card.image = [UIImage imageNamed:#"goodguyPINK.png"];
}
else if (randomColor == 2)
{
_card.image = [UIImage imageNamed:#"goodGuyPURPLE.png"];
}
else if (randomColor == 3)
{
_card.image = [UIImage imageNamed:#"goodGuyORANGE.png"];
}
else if (randomColor == 4)
{
_card.image = [UIImage imageNamed:#"goodGuyLightPINK.png"];
}
else if (randomColor == 5)
{
_card.image = [UIImage imageNamed:#"goodGuyBLUE.png"];
}
else if (randomColor == 6)
{
_card.image = [UIImage imageNamed:#"goodGuyGREEN.png"];
}
_card.userInteractionEnabled = YES; // this is also written in my viewDidLoad method
[[_card.layer presentationLayer] hitTest:origini]; // not really sure what this does
[self.view addSubview:_card];
int randomSpeed = rand() % 20;
int randomDelay = rand() % 2;
[UIView animateWithDuration:randomSpeed + 10
delay: randomDelay + 4
options:UIViewAnimationOptionAllowUserInteraction // here is the method that I thought would allow me to interact with the moving cards. Not sure why I can't
animations: ^{
_card.frame = cardFramei;
}
completion:NULL];
}
}
notice the following method is where I put CALayer and hit test information. I'm not sure if I'm doing this correctly.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *t = [touches anyObject];
UIView *myTouchedView = [t view];
CGPoint thePoint = [t locationInView:self.view];
thePoint = [self.view.layer convertPoint:thePoint toLayer:self.view.layer.superlayer];
CALayer *theLayer = [self.view.layer hitTest:thePoint];
if([_card.layer.presentationLayer hitTest:thePoint])
{
NSLog(#"You touched a Shape!"); // This only logs when I touch a non-moving shape
}
else{
NSLog(#"backgound touched"); // this logs when I touch the background or an moving shape.
}
if(myTouchedView == _card)
{
NSLog(#"Touched a card");
_boolHasCard = YES;
}
else
{
NSLog(#"Didn't touch a card");
_boolHasCard = NO;
}
}
I want the following method to work on moving shapes. It only works on non-moving shapes. Many answers say to have the touch ask which class the card is from. As of now all my cards on of the same class (the viewController class). When trying to have the cards be their own class, I was having trouble having that view appear on my main background controller. Must I have various cards be from different classes for this to work, or can I have it work without needing to do so?
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
if([touch view]==self.card)
{
CGPoint location = [touch locationInView:self.view];
self.card.center=location;
}
}
This next method resets the movement of a card if the user starts moving it and then lifts up on it.
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if(_boolHasCard == YES)
{
[UIView animateWithDuration:3
delay: 0
options:UIViewAnimationOptionAllowUserInteraction
animations: ^{
CGRect newCardOrigin = CGRectMake(1200,_card.center.y - 92/2, 92, 87);
_card.frame = newCardOrigin;
}
completion:NULL];
}
}
#end
The short answer is, you can't.
Core Animation does not actually move the objects along the animation path. They move the presentation layer of the object's layer.
The moment the animation begins, the system thinks the object is at it's destination.
There is no way around this if you want to use Core Animation.
You have a couple of choices.
You can set up a CADisplayLink on your view controller and roll your own animation, where you move the center of your views by a small amount on each call to the display link. This might lead to poor performance and jerky animation if you're animating a lot of objects however.
You can add a gesture recognizer to the parent view that contains all your animations, and then use layer hit testing on the paren't view's presentation view to figure out which animating layer got tapped, then fetch that layer's delegate, which will be the view you are animating. I have a project on github that shows how to do this second technique. It only detects taps on a single moving view, but it will show you the basics: Core Animation demo project on github.
(up-votes always appreciated if you find this post helpful)
It looks to me that your problem is really with just an incomplete understanding of how to convert a point between coordinate spaces. This code works exactly as expected:
- (void)viewDidLoad
{
[super viewDidLoad];
CGPoint endPoint = CGPointMake([[self view] bounds].size.width,
[[self view] bounds].size.height);
CABasicAnimation *animation = [CABasicAnimation
animationWithKeyPath:#"position"];
animation.fromValue = [NSValue valueWithCGPoint:[[_imageView layer] position]];
animation.toValue = [NSValue valueWithCGPoint:endPoint];
animation.duration = 30.0f;
[[_imageView layer] addAnimation:animation forKey:#"position"];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *t = [touches anyObject];
CGPoint thePoint = [t locationInView:self.view];
thePoint = [[_imageView layer] convertPoint:thePoint
toLayer:[[self view] layer]];
if([[_imageView layer].presentationLayer hitTest:thePoint])
{
NSLog(#"You touched a Shape!");
}
else{
NSLog(#"backgound touched");
}
}
Notice the line in particular:
thePoint = [[_imageView layer] convertPoint:thePoint
toLayer:[[self view] layer]];
When I tap on the layer image view while it's animating, I get "You touched a Shape!" in the console window and I get "background touched" when I tap around it. That's what you're wanting right?
Here's a sample project on Github
UPDATE
To help with your follow up question in the comments, I've written the touchesBegan code a little differently. Imagine that you've add all of your image views to an array (cleverly named imageViews) when you create them. You would alter your code to look something like this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *t = [touches anyObject];
CGPoint thePoint = [t locationInView:self.view];
for (UIImageView *imageView in [self imageViews]) {
thePoint = [[imageView layer] convertPoint:thePoint
toLayer:[[self view] layer]];
if([[imageView layer].presentationLayer hitTest:thePoint]) {
NSLog(#"Found it!!");
break; // No need to keep iterating, we've found it
} else{
NSLog(#"Not this one!");
}
}
}
I'm not sure how expensive this is, so you may have to profile it, but it should do what you're expecting.

How to add images while moving finger across UIView?

I am having issues adding an image across a view while moving finger across the screen.
Currently it is adding the image multiple times but squeezing them too close together and not really following my touch.
EDIT:
What I want:
After taking or choosing an image, the user can then select another image from a list. I want the user to touch and move their finger across the view and the selected image will appear where they drag their finger, without overlapping, in each location.
This works:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
currentTouch = [touch locationInView:self.view];
CGRect myImageRect = CGRectMake(currentTouch.x, currentTouch.y, 80.0f, 80.0f);
myImage = [[UIImageView alloc] initWithFrame:myImageRect];
[myImage setImage:[UIImage imageNamed:#"dot.png"]];
[self.view addSubview:myImage];
[myImage release];
}
New Question: How do I add spaces in this so that the image isn't so snug when drawing it on the view?
You might want to explain your question more, what exactly are you trying to achieve! If you dont want the images to overlap than you can try this!
UITouch * touch = [touches anyObject];
touchPoint = [touch locationInView:imageView];
prev_touchPoint = [touch previousLocationInView:imageView];
if (ABS(touchPoint.x - prev_touchPoint.x) > 80
|| ABS(touchPoint.y - prev_touchPoint.y) > 80) {
_aImageView = [[UIImageView alloc] initWithImage:aImage];
_aImageView.multipleTouchEnabled = YES;
_aImageView.userInteractionEnabled = YES;
[_aImageView setFrame:CGRectMake(touchPoint.x, touchPoint.y, 80.0, 80.0)];
[imageView addSubview:_aImageView];
[_aImageView release];
}
I'm sorry because I'm in company and I can't post too big data(the code). The squeezing is because you have not checked the touch point's distance with last touch point. Check a point whether it's in a view:bool CGRectContainsPoint (CGRect rect,CGPoint point);I mean remember a touch point in touchesBegan:. Update it if the new touches in touchesMomved: is bigger than image's width or left. And put the add image view in a method and call it use - (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg.
you can also use UISwipeGestureRecognizer as below instead of touchesMoved method,while swiping across the screen.in viewDidload:method,
UISwipeGestureRecognizer *swipeup = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipedone:)];
swipeup.direction = UISwipeGestureRecognizerDirectionUp;
swipeup.numberOfTouchesRequired=1;
[self.view addGestureRecognizer:swipeup];
method definition:
-(IBAction)swipedone:(UISwipeGestureRecognizer*)recognizer
{
NSLog(#"swiped");
UIImageView* _aImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"1.png"]];
_aImageView.frame = CGRectMake(10, 10, 100, 100);
_aImageView.multipleTouchEnabled = YES;
_aImageView.userInteractionEnabled = YES;
CGPoint point = [recognizer locationInView:recognizer.view];
[_aImageView setFrame:CGRectMake(point.x, point.y, 80.0, 80.0)];
[self.view addSubview:_aImageView];
[_aImageView release];
}
currently i am using this code for swipe up.i think it will works fine.once try it.

How can I make a UIImageView follow a certain path? [duplicate]

I am developing a simple animation where an UIImageView moves along a UIBezierPath, now I want to provide user interation to the moving UIImageView so that user can guide the UIImageView by touching the UIImageView and drag the UIImageview around the screen.
Change the frame of the position of the image view in touchesMoved:withEvent:.
Edit: Some code
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
UITouch *touch = [[event allTouches] anyObject];
if ([touch.view isEqual: self.view] || touch.view == nil) {
return;
}
lastLocation = [touch locationInView: self.view];
}
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
UITouch *touch = [[event allTouches] anyObject];
if ([touch.view isEqual: self.view]) {
return;
}
CGPoint location = [touch locationInView: self.view];
CGFloat xDisplacement = location.x - lastLocation.x;
CGFloat yDisplacement = location.y - lastLocation.y;
CGRect frame = touch.view.frame;
frame.origin.x += xDisplacement;
frame.origin.y += yDisplacement;
touch.view.frame = frame;
lastLocation=location;
}
You should also implement touchesEnded:withEvent: and touchesCanceled:withEvent:.
So you want the user to be able to touch an image in the middle of a keyframe animation along a curved path, and drag it to a different location? What do you want to happen to the animation at that point?
You have multiple challenges.
First is detecting the touch on the object while a keyframe animation is "in flight".
To do that, you want to use the parent view's layer's presentation layer's hitTest method.
A layer's presentation layer represents the state of the layer at any given instant, including animations.
Once you detect touches on your view, you will need to get the image's current location from the presentation layer, stop the animation, and take over with a touchesMoved/touchesDragged based animation.
I wrote a demo application that shows how to detect touches on an object that's being animated along a path. That would be a good starting point.
Take a look here:
Core Animation demo including detecting touches on a view while an animation is "in flight".
Easiest way would be subclassing UIImageView.
For simple dragging take a look at the code here (code borrowed from user MHC):
UIView drag (image and text)
Since you want to drag along Bezier path you'll have to modify touchesMoved:
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *aTouch = [touches anyObject];
//here you have location of user's finger
CGPoint location = [aTouch locationInView:self.superview];
[UIView beginAnimations:#"Dragging A DraggableView" context:nil];
//commented code would simply move the view to that point
//self.frame = CGRectMake(location.x-offset.x,location.y-offset.y,self.frame.size.width, self.frame.size.height);
//you need some kind of a function
CGPoint calculatedPosition = [self calculatePositonForPoint: location];
self.frame = CGRectMake(calculatedPosition.x,calculatedPosition.y,self.frame.size.width, self.frame.size.height);
[UIView commitAnimations];
}
What exactly you would like to do in -(CGPoint) calculatePositionForPoint:(CGPoint)location
is up to you. You could for example calculate point in Bezier path that is the closest to location. For simple test you can do:
-(CGPoint) calculatePositionForPoint:(CGPoint)location {
return location;
}
Along the way you're gonna have to decide what happens if user wonders off to far from your
precalculated Bezier path.

How to add movable UIView as subview with dynamic size at runtime in objective C?

I need to add a UIView as subview of a UIView where a UIImageview is displayed. What I need to implement is that when the image is loaded in my UIIMageview, at the same time I am showing the UIView call it as newView. In the beginning,I am showing it with static size say 190X170 and alpha as 0.5. Once i tap my finger on that view,it should move on the whole UIImageview. Once it is moved at the last,that coordinated I am taking and cropping my image with the same points. Now I am done with the moving part using the code below.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (CGRectContainsPoint(newView.frame, touchLocation))
{
dragging = YES;
oldX = touchLocation.x;
oldY = touchLocation.y;
}
if (dragging)
{
newView.layer.borderColor = [UIColor clearColor].CGColor;
newView.layer.borderWidth = 1.0f;
CGRect frame = newView.frame;
frame.origin.x = newView.frame.origin.x + touchLocation.x - oldX;
x = frame.origin.x;
NSLog(#"x value : %d",x);
frame.origin.y = newView.frame.origin.y + touchLocation.y - oldY;
y = frame.origin.y;
NSLog(#"y value : %d",y);
newView.frame = frame;
}
oldX = touchLocation.x;
oldY = touchLocation.y;
}
What I need to implement is to resize the UIView on taping two fingers like that of UIScrollview. I tried to implement the UIScrollview but it is not giving me good effect. I tried to implement
NSUInteger resizingMask = NSViewHeightSizable | NSViewWidthSizable;
[self.view setAutoresizesSubviews:YES];
[newView setAutoresizingMask:resizingMask];
but in vain. Nothing is taking place.
Can anybody show me a path for the same. Thanks in advance.
To provide the zoom in zoom out feature you can use the UIPinchGuestureRecognizer. If you are using iOS 5 then it will be pretty easy for you.
here is the very cool tutorial for that hope it will help for you.
http://www.raywenderlich.com/6567/uigesturerecognizer-tutorial-in-ios-5-pinches-pans-and-more

Control the animation by touch

i have this type of code....
// create a UIImageView
UIImageView *rollDiceImageMainTemp = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"rollDiceAnimationImage1.png"]];
// position and size the UIImageView
rollDiceImageMainTemp.frame = CGRectMake(0, 0, 100, 100);
// create an array of images that will represent your animation (in this case the array contains 2 images but you will want more)
NSArray *savingHighScoreAnimationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"rollDiceAnimationImage1.png"],
[UIImage imageNamed:#"rollDiceAnimationImage2.png"],
nil];
// set the new UIImageView to a property in your view controller
self.viewController.rollDiceImage = rollDiceImageMainTemp;
// release the UIImageView that you created with alloc and init to avoid memory leak
[rollDiceImageMainTemp release];
// set the animation images and duration, and repeat count on your UIImageView
[self.viewController.rollDiceImageMain setAnimationImages:savingHighScoreAnimationImages];
[self.viewController.rollDiceImageMain setAnimationDuration:2.0];
[self.viewController.rollDiceImageMain.animationRepeatCount:3];
// start the animation
[self.viewController.rollDiceImageMain startAnimating];
// show the new UIImageView
[self.viewController.view addSubview:self.rollDiceImageMain];
Instead of startAnimation directly..there any way to control this code using touchesMoved??
Actually, what you want is the - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event. Below is a sample of code that will allow a UIView to move on the x-axis only. Adapt to whatever you need your code to do.
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
CGPoint original = self.center;
UITouch* touch = [touches anyObject];
CGPoint location = [touch locationInView:self.superview];
// Taking the delta will give us a nice, smooth movement that will
// track with the touch.
float delta = location.x - original.x;
// We need to substract half of the width of the view
// because we are using the view's center to reposition it.
float maxPos = self.superview.bounds.size.width
- (self.frame.size.width * 0.5f);
float minPos = self.frame.size.width * 0.5f;
float intendedPos = delta + original.x;
// Make sure they can't move the view off-screen
if (intendedPos > maxPos)
{
intendedPos = maxPos;
}
// Make sure they can't move the view off-screen
if (intendedPos < minPos)
{
intendedPos = minPos;
}
self.center = CGPointMake(intendedPos, original.y);
// We want to cancel all other touches for the view
// because we don't want the touchInside event firing.
[self touchesCancelled:touches withEvent:event];
// Pass on the touches to the super
[super touchesMoved:touches withEvent:event];
}
Notice here that I am taking the delta of the movement and not with the finger. If you track with the finger you will get very erratic behavior that is very undesirable. Applying the delta will give nice, fluid movement of the view that will track perfectly with the touch input.
Update: Also, for those wondering why I chose to multiply by 0.5f rather than divide by 2, the ARM processor doesn't support division in hardware, so there is a minuscule performance bump by going with multiplication. This performance optimization may only get called only a few times during the life of a program so it might not make a difference, but this particular message is called many, many times when dragging. Because it is in this case, it might be worth the multiplication, instead.
You can detect touches by using UIResponder methods like - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event in that you can call the [self.viewController.rollDiceImageMain startAnimating]; method.
And once it starts then you can stop after some time and restrict the touches.