Question

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.

Was it helpful?

Solution

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".

OTHER TIPS

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:.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top