Animate a UIImageView in the middle of an animation - iphone

I have an object that is moving right to left across the screen:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:7.8];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
myImageview.layer.position = CGPointMake(20, myImageView.layer.position.y);
[UIView commitAnimations];
I found out that even while the animation is still happening, XCode already marks the image's location as its final destination, and in order to detect a touch on the moving image, I need to use the presentationLayer:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
if ([myImageview.layer.presentationLayer hitTest:touchPoint]) {
NSLog(#"it's a hit!");
}
}
This part works.
Now, I'd like the image to move up when it is pressed.
I want the image to move up while it continues it's sideways movement.
Instead, this code moves the image not just up, but also all the way to its final destination on the left:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
if ([mouse.layer.presentationLayer hitTest:touchPoint]) {
NSLog(#"it's a hit!");
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
myImageView.layer.position = CGPointMake( mouse.layer.position.x, myImageView.layer.position.y - 40);
[UIView commitAnimations];
}
}
I want the image to move up while it continues it's sideways movement.
Does anyone know of a way to accomplish this?
Thanks so much!

Have you tried setting the animation option UIViewAnimationOptionBeginFromCurrentState?
(I say option because it is an option in the block-based animation methods introduced with iOS 4. It is also available as [UIView setAnimationBeginsFromCurrentState:YES] if you can't switch away from the deprecated UIView class methods just yet.)
touchesBegan becomes (using block animations):
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
if ([mouse.layer.presentationLayer hitTest:touchPoint]) {
NSLog(#"it's a hit!");
[UIView animateWithDuration:0.5 delay:0.0 options:(UIViewAnimationOptionCurveLinear & UIViewAnimationOptionBeginFromCurrentState) animations:^{
myImageView.layer.position = CGPointMake( myImageView.layer.position.x, mouse.layer.position.y - 40);
}completion:^(BOOL complete){
//
}];
}
}
If you use that you should be able to specify the final x and y coordinates you want and have animation proceed from the point at which the object was touched to that position.

Related

Iphone SDK: move and rotate to touch

I have an image of a fish - If the user touches the screen I want the fish to "look" at the touched point and move there. If the touch has been moved i want the fish constantly following the touch.
How can I do that?
would be something like this:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *tap = [touches anyObject];
CGPoint pointToMove = [tap locationInView:self.view];
CGFloat xdiff = pointToMove.x-myFish.center.x;
CGFloat ydiff = pointToMove.y-myFish.center.y;
if (!CGRectContainsPoint(myFish.frame, pointToMove)) {
CGFloat angle = 0;
if (xdiff) {
if (xdiff>0) {
angle = atanf(ydiff/xdiff);
} else {
angle = M_PI + atanf(ydiff/xdiff);
}
}
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3f];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
myFish.transform = CGAffineTransformMakeRotation(angle);
[UIView commitAnimations];
}
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0f];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
myFish.center = pointToMove;
[UIView commitAnimations];
}
and you probably want to implement these too:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
EDIT: updated code, now the rotation is done in a separate animation, so that the fish rotates faster than he swims.

moving UITextField in UIView

i am using UITextField on my UIView and need to drag UITextField with my pointer on my UIView but its not working!! here is my code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[UIView beginAnimations:#"Move" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationBeginsFromCurrentState:YES];
UITouch *touch = [[event allTouches] anyObject];
mytextField.center = [touch locationInView:myView];
[UIView commitAnimations]; }
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
mytextField.center = [touch locationInView:myView];}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{}
You wanna move to UITextField with touches then use this code -
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint pt = [[touches anyObject] locationInView:textFieldObj];
// textFieldObj is your UITextfield
startLocationOfText = pt;
//startLocationOfText is just CGPoint declared globaly
}
now touches moved method
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint pt = [[touches anyObject] previousLocationInView:textField2];
CGFloat dx = pt.x - startLocationOfText.x;
CGFloat dy = pt.y - startLocationOfText.y;
CGPoint newCenter = CGPointMake(textFieldObj.center.x + dx, textFieldObj.center.y + dy);
textFieldObj.center = newCenter;
}
You can comments the touchesBegan method but for clear move you should keep this method.
Thank you!
Why you have taken animation in touches began.I think just comment code of touches began and try it will work.

UIView drag (image and text)

Is it possible to drag UIView around the iOS screen while it has both image and text? e.g. small cards. Could you point me to the similar (solved) topic? I haven't found any.
This is what a neat solution, based on pepouze's answer, would look like (tested, it works!)
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *aTouch = [touches anyObject];
CGPoint location = [aTouch locationInView:self];
CGPoint previousLocation = [aTouch previousLocationInView:self];
self.frame = CGRectOffset(self.frame, (location.x - previousLocation.x), (location.y - previousLocation.y));
}
While UIView does not have a built-in support for moving itself along the user dragging, it should be not so difficult to implement it. It is even easier when you are only dealing with dragging on the view, and not other actions such as tapping, double tapping, multi-touches etc.
First thing to do is to make a custom view, say DraggableView, by subclassing UIView. Then override UIView's touchesMoved:withEvent: method, and you can get a current dragging location there, and move the DraggableView. Look at the following example.
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *aTouch = [touches anyObject];
CGPoint location = [aTouch locationInView:self.superview];
[UIView beginAnimations:#"Dragging A DraggableView" context:nil];
self.frame = CGRectMake(location.x, location.y,
self.frame.size.width, self.frame.size.height);
[UIView commitAnimations];
}
And because all subviews of the DraggableView object will be moved, too. So put all your images and texts as subviews of the DraggableView object.
What I implemented here is very simple. However, if you want more complex behaviors for the dragging, (for example, the user have to tap on the view for a few seconds to move the view), then you will have to override other event handling methods (touchesBegan:withEvent: and touchesEnd:withEvent) as well.
An addition to MHC's answer.
If you don't want the upper left corner of the view
to jump under your finger, you can also override touchesBegan
like this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *aTouch = [touches anyObject];
offset = [aTouch locationInView: self];
}
and change MHC's touchesMoved to:
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *aTouch = [touches anyObject];
CGPoint location = [aTouch locationInView:self.superview];
[UIView beginAnimations:#"Dragging A DraggableView" context:nil];
self.frame = CGRectMake(location.x-offset.x, location.y-offset.y,
self.frame.size.width, self.frame.size.height);
[UIView commitAnimations];
}
you should also define CGPoint offset in the interface:
#interface DraggableView : UIView
{
CGPoint offset;
}
EDIT:
Arie Litovsky provides more elegant solution that allows you to ditch the ivar: https://stackoverflow.com/a/10378382/653513
Even though rokjarc solution works, using
CGPoint previousLocation = [aTouch previousLocationInView:self.superview];
avoids the CGPoint offset creation and the call to touchesBegan:withEvent:
Here is a solution to drag a custom UIView (it can be scaled or rotated through its transform), which can hold images and/or text (just edit the Tile.xib as required):
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
CGPoint previous = [touch previousLocationInView:self];
if (!CGAffineTransformIsIdentity(self.transform)) {
location = CGPointApplyAffineTransform(location, self.transform);
previous = CGPointApplyAffineTransform(previous, self.transform);
}
self.frame = CGRectOffset(self.frame,
(location.x - previous.x),
(location.y - previous.y));
}
This work for me. My UIView rotated and scaled
- (void) touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
CGPoint previous = [touch previousLocationInView:self];
if (!CGAffineTransformIsIdentity(self.transform)) {
location = CGPointApplyAffineTransform(location, self.transform);
previous = CGPointApplyAffineTransform(previous, self.transform);
}
CGRect newFrame = CGRectOffset(self.frame,
(location.x - previous.x),
(location.y - previous.y));
float x = CGRectGetMidX(newFrame);
float y = CGRectGetMidY(newFrame);
self.center = CGPointMake(x, y);
}

iPhone: Move UIImageView continuously with swipe

I want to move an image (cBlock) continuously with a gesture. The direction of the swipe gesture determines the direction of the movement. I am able to move, but not continuously. Although the finger is held down, the movement starts/stops. Can anyone see why?
I believe touchesMoved is called continuously, as the log statements appear to be firing off continuously. Also, this logic does not seem to account for the finger being held down while the direction becomes positive, then negative (ex. users pans right, then pans left without lifting finger.) Is there a proven solution for that case?
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
gestureStartPoint = [touch locationInView:gridView];
prevGesturePoint = gestureStartPoint;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView:gridView];
CGFloat deltaX = currentPosition.x - prevGesturePoint.x;
CGFloat deltaY = currentPosition.y - prevGesturePoint.y;
if(running == YES){
if(fromTop || fromBottom){
if((currentPosition.x - prevGesturePoint.x) > 0) {
NSLog(#"swipe right.");
[cBlock movXSinglePixel:10]; // move 10px
} else if((currentPosition.x - prevGesturePoint.x) < 0) {
NSLog(#"swipe left.");
[cBlock movXSinglePixel:-10]; //move -10px
}
}
}
[container setNeedsDisplay];
prevGesturePoint = currentPosition;
}
- (void)movXSinglePixel:(int)dir{
[UIView beginAnimations:#"center" context:nil];
[UIView setAnimationDuration:0.01];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
if(tX + dir > 8 || tX + dir < 0){
// Attempt to move out of grid bounds.
return;
}
CGPoint center = [self center];
center.x += (dir * 1.0f);
[self setCenter:center];
tX += dir;
[UIView commitAnimations];
}

iPhone/Cocoa Animation having effect I don't understand

I have created a basic unlock slider like you use to unlock the iPhone.
In my touchesEnded function, I use an animation to move the slider back to home.
The first time the user moves the slider (and doesn't actually hit the end to unlock), the animation works fine and the slider moves back to home.
However, the next time the user tries to move the slider (and touchesMoved gets called), the slider gets pushed offscreen (to the left) by the amount they had slid the slider before.
So, what's happening?
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
self.dragging = NO;
self.startX = 0;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
self.unlock.frame = CGRectMake(0, 0, 75, 35);
[UIView commitAnimations];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (!self.dragging ) { return; }
UITouch *touch = [[event allTouches] anyObject];
CGPoint point = [touch locationInView:self];
int offset = point.x - self.startX;
NSLog(#"%i", offset);
if (offset > (LENGTH-SIZE)) {
offset = (LENGTH-SIZE);
}
CGAffineTransform myTransform = CGAffineTransformMakeTranslation(offset, 0.0);
[self.unlock setTransform:myTransform];
if (point.x >= (LENGTH-(SIZE-self.startX))) {
NSLog(#"Slider reached end");
[self.sliderView removeFromSuperview];
}
}
EDIT
Here's the working function, cleaned up a bit, though it could be better (thanks to a couple answered questions on SO from one hacker). I'm going to blog the complete module since there doesn't seem to be a standard widget:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (!self.dragging ) { return; }
UITouch *touch = [[event allTouches] anyObject];
CGPoint point = [touch locationInView:self];
if (point.x >= (LENGTH-(SIZE-self.startX))) {
NSLog(#"Slider reached end");
[self.sliderView removeFromSuperview];
}
// offset based on where the user clicked the slider
int offset = point.x - self.startX;
if (offset > (LENGTH-SIZE)) {
offset = (LENGTH-SIZE);
}
//move the slider
CGRect oldFrame = self.unlock.frame;
CGRect newFrame = CGRectMake(self.frame.origin.x+offset, self.frame.origin.y-5, oldFrame.size.width, oldFrame.size.height);
self.unlock.frame = newFrame;
}
IN your previous question I didn't realize you were moving the slider by changing its transform. Mixing up motion by changing its frame and transform is going to be moderately complicated.
Maybe you could try doing something more like this:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (!self.dragging ) { return; }
UITouch *touch = [[event allTouches] anyObject];
CGPoint point = [touch locationInView:self];
int offset = point.x - self.startX;
NSLog(#"%i", offset);
if (offset > (LENGTH-SIZE)) {
offset = (LENGTH-SIZE);
}
CGRect oldFrame = self.frame;
CGRect newFrame = CGRectMake(oldFrame.origin.x+offset, oldFrame.origin.y, oldFrame.size.width, oldFrame.size.height);
self.frame = newFrame;
if (point.x >= (LENGTH-(SIZE-self.startX))) {
NSLog(#"Slider reached end");
[self.sliderView removeFromSuperview];
}
}
That moves the slider by modifying its frame, not its translation, which should cause it to interact better with the snap back animation. Alternatively, rather than resetting the frame in the implicit animator you could reset the translation there.
You need to reset the view transform in your touchesEnded handler:
[self.unlock setTransform:CGAffineTransformIdentity];
Try that instead of animating the frame property.