Frage

DO NOT POST ANSWERS ABOUT UIVIEW ANIMATIONS I understand UIView, I am learning core-animation. Im trying to get an image to move 50 units to the right but I am having many issues. First when the animation is called the image jumps to a new location, runs, then jumps back to the original location. I want it to simply move 50 units to the right, stop, move again if the button is pressed. I have spent a lot of time researching and I can't seem to find the problem. My Code:

-(IBAction)preform:(id)sender{

CGPoint point = CGPointMake(imView.frame.origin.x, imView.frame.origin.y);
imView.layer.position = point;

CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position.x"];
anim.fromValue  = [NSValue valueWithCGPoint:point];
anim.toValue    = [NSValue valueWithCGPoint:CGPointMake(point.x + 50, point.y)];
anim.duration   = 1.5f;
anim.repeatCount =1;
anim.removedOnCompletion = YES;
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
[imView.layer  addAnimation:anim forKey:@"position.x"];
imView.layer.position = point;

}
War es hilfreich?

Lösung

I see several problems in your code.

First, you're grabbing the frame origin like this:

CGPoint point = CGPointMake(imView.frame.origin.x, imView.frame.origin.y);

Although it's not really a problem, you could simply do this:

CGPoint point = imView.frame.origin;

The problem is that you're setting the layer's position to its frame's origin. But by default, the position controls the center of the view, and the frame's origin is its upper-left corner. You probably want to just pick up the layer's position in the first place:

CGPoint point = imView.layer.position; // equivalent to imView.center

Second, you're using the position.x key path, which wants a CGFloat value, but you're providing a CGPoint value. This doesn't appear to cause a problem in the iOS 6.1 simulator, but it's probably a bad idea to assume it will always work.

Third, you need to understand that an animation does not change the properties of your layer! Each of the layers you normally manipulate (technically called a model layer) has an associated presentation layer. The presentation layer's properties control what is on the screen. When you change a model layer's property, Core Animation usually sets up an animation (from the old value to the new value) on the presentation layer automatically. This is called an implicit animation. A UIView suppresses implicit animations on its layer.

When the animation on the presentation layer ends and is removed, the presentation layer's properties revert to its model layer's values. So to make the change permanent, you need to update the model layer's properties. Generally it's best to update the model layer's properties first, then add the animation, so that your explicit animation overwrites the implicit animation (if one was created).

As it happens, although you can animate position.x, you need to set position on the model layer to make it stick. I tested this to work:

- (IBAction)perform:(id)sender {
    CGPoint point0 = imView.layer.position;
    CGPoint point1 = { point0.x + 50, point0.y };

    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position.x"];
    anim.fromValue    = @(point0.x);
    anim.toValue  = @(point1.x);
    anim.duration   = 1.5f;
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

    // First we update the model layer's property.
    imView.layer.position = point1;

    // Now we attach the animation.
    [imView.layer  addAnimation:anim forKey:@"position.x"];
}

(Note that I called my method perform:. The method in the original post seems to be misspelled.)

If you want to really understand Core Animation, I highly recommend watching the Core Animation Essentials video from WWDC 2011. It's an hour long and contains a ton of useful information.

Andere Tipps

This is what you should need to get it working. The position on the layer is already set so you can use that as the fromValue and just modify it to get the toValue. The other important step is to set the layers position to be endPos so that when the animation finishes, the image view will stay at the correct position.

-(IBAction)preform:(id)sender
{
    CGPoint startPos = imView.layer.position;
    CGPoint endPos = CGPointMake(point.x + 50, point.y);

    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position.x"];
    anim.fromValue  = [NSValue valueWithCGPoint:startPos];
    anim.toValue    = [NSValue valueWithCGPoint:endPos];
    anim.duration   = 1.5f;
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

    [imView.layer addAnimation:anim forKey:@"position.x"];
    imView.layer.position = endPos;
}

jumping back is caused by the fact that you remove animation on completion

anim.removeOnCompletion = NO;

EDIT #3: just copied and tried your code here is the fix for all of your issues, pretty much self explanatory :

CGPoint point = imView.center;
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position.x"];
anim.fromValue  = [NSNumber numberWithFloat:point.x];
anim.toValue    = [NSNumber numberWithFloat:point.x+50.0];//[NSValue valueWithCGPoint:CGPointMake(point.x + 50, point.y)];
anim.duration   = 1.5f;
anim.repeatCount =1;
anim.removedOnCompletion = NO;
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
anim.fillMode=kCAFillModeForwards;
[imView.layer  addAnimation:anim forKey:@"position.x"];
[sender.layer  addAnimation:anim forKey:@"position.x"];
sender.layer.position=CGPointMake(point.x+50.0,sender.layer.position.y);

That fact that it jumps back even though removedOnCompletion is set to no is a head scratcher. Still playing around with it.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top