5

Possible Duplicate:
Android, move bitmap along a path?

I want to move an image through a curved path.Is it possible in android ? I searched a lot but i can only find about scale,rotate and translate animation.So anyone have any idea please help.Is it possible in android?

Community
  • 1
  • 1
Android Killer
  • 18,174
  • 13
  • 67
  • 90
  • See this answer: [Prepare curve translate animation in Android](http://stackoverflow.com/questions/8354441/how-to-prepare-curve-translate-animation-for-android/27948353#27948353) – Sheharyar Jan 14 '15 at 16:59

4 Answers4

9

Below is fully functioning code that will animate along a curved path defined by three points. A Point is just a class holding an x value and a y value (though you could easily extend it for more dimensions).

All the m variables are taken from TranslateAnimation and used in in a similar manner, so you should be able to compare it to the TranslateAnimation code relatively eaSILY if something doesn't make sense.

The calls to resolveSize in initialize mean that you can specify the start, end, and radius of the arc using any of the Animation types (ABSOLUTE, RELATIVE_TO_SELF, RELATIVE_TO_PARENT) just as you would for a normal TranslateAnimation.

calcBezier calculates the quadratic bezier curve taken directly from Wikipedia. The Bezier curve is supposed to allow for smooth scaling and is common in graphics (and also used in Android's Path class).

The actual movement happens in applyTransformation. interpolatedTime gives a value between 0 and 1, which increases nonlinearly depending on the interpolator provided. dx and dy are the actual x and y points along the curve for the given time.

The only limitation of this class is that the largest change in y always occurs at the center of the curve (see the calculation for middleX in initialize). However it would be easy to modify, for example, to give a particular point along the curve at which the high point should occur if you want a non-symmetric curve.

Looking at the android code for TranslateAnimation was particularly helpful. See: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3.5_r1/android/view/animation/TranslateAnimation.java#TranslateAnimation

public class ArcTranslate extends Animation {

private Point start;
private Point end;
private Point middle;
private final float mFromXValue;
private final float mToXValue;
private final float mYValue;
private final int mFromXType;
private final int mToXType;
private final int mYType;

/**
 * A translation along an arc defined by three points and a Bezier Curve
 *
 * @param duration - the time in ms it will take for the translation to complete
 * @param fromXType - One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or Animation.RELATIVE_TO_PARENT.
 * @param fromXValue - Change in X coordinate to apply at the start of the animation
 * @param toXType - One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or Animation.RELATIVE_TO_PARENT.
 * @param toXValue - Change in X coordinate to apply at the end of the animation
 * @param yType - One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or Animation.RELATIVE_TO_PARENT.
 * @param yValue - Change in Y coordinate to apply at the middle of the animation (the radius of the arc)
 */
public ArcTranslate(long duration, int fromXType, float fromXValue,
        int toXType, float toXValue, int yType, float yValue){
    setDuration(duration);

     mFromXValue = fromXValue;
     mToXValue = toXValue;
     mYValue = yValue;

     mFromXType = fromXType;
     mToXType = toXType;
     mYType = yType;

}

/** Calculate the position on a quadratic bezier curve given three points
 *  and the percentage of time passed.
 * from http://en.wikipedia.org/wiki/B%C3%A9zier_curve
 * @param interpolatedTime - the fraction of the duration that has passed where 0<=time<=1
 * @param p0 - a single dimension of the starting point
 * @param p1 - a single dimension of the middle point
 * @param p2 - a single dimension of the ending point
 */
private long calcBezier(float interpolatedTime, float p0, float p1, float p2){
    return Math.round((Math.pow((1 - interpolatedTime), 2) * p0)
           + (2 * (1 - interpolatedTime) * interpolatedTime * p1)
           + (Math.pow(interpolatedTime, 2) * p2));
}

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
    float dx = calcBezier(interpolatedTime, start.x, middle.x, end.x);
    float dy = calcBezier(interpolatedTime, start.y, middle.y, end.y);

    t.getMatrix().setTranslate(dx, dy);
}

@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
    super.initialize(width, height, parentWidth, parentHeight);
    float startX = resolveSize(mFromXType, mFromXValue, width, parentWidth);
    float endX = resolveSize(mToXType, mToXValue, width, parentWidth);
    float middleY = resolveSize(mYType, mYValue, width, parentWidth);
    float middleX = startX + ((endX-startX)/2);
    start = new Point(startX, 0);
    end = new Point(endX, 0);
    middle = new Point(middleX, middleY);
}
}
Marios
  • 165
  • 1
  • 8
Sam Judd
  • 7,317
  • 1
  • 38
  • 38
  • @Monkeyless Thank you so much for the code. I managed to animate an imageview using this code. But I am having trouble in setting an onClickListener to an imageview while it is animating. I have posted a question [here](http://stackoverflow.com/questions/23947114/onclicklistener-not-triggered-during-animation). Please help. – jincy abraham May 30 '14 at 04:38
5

It was inspired by Monkeyless's answer. I created a subclass of Animation, use PathMeasure to calculate the translation. You can just create a new PathAnimation with a Path, and use it like any other Animations.

https://github.com/coocood/PathAnimation

public class PathAnimation extends Animation {
private PathMeasure measure;
private float[] pos = new float[2];
public PathAnimation(Path path) {
    measure = new PathMeasure(path, false);
}

@Override
protected void applyTransformation(float interpolatedTime, Transformation t){
    measure.getPosTan(measure.getLength() * interpolatedTime, pos,null);
    t.getMatrix().setTranslate(pos[0], pos[1]);
}
}
coocood
  • 1,376
  • 11
  • 8
  • I've used Path.addArc() to create the arc I want my View to travel on, and then this solution as the animation itself. Nice! – Vaiden Dec 09 '13 at 21:21
  • @vaiden, Can you post the example here? – Geetha Aug 26 '15 at 06:05
  • 1
    Just create a Path object and feed it to the constructor. There isn't really an example. – Vaiden Aug 26 '15 at 06:06
  • Can I create Path like the below to do the curved animation? Where would I give the image reference. I want to move the image in curved animation // Init the Path. path=new Path(); // Set the starting position of the path to (0,0). path.moveTo(0,0); // Add a line to the Path, starting from (0,0), ending at (100, 100). path.addArc(0,0,0,0,0,270); – Geetha Aug 26 '15 at 06:23
  • Sorry, I cannot use addArc(). My app min API is 18 – Geetha Aug 26 '15 at 06:32
  • Looks amazingly simple but I can't get the Path to work? I'm not sure if it's the Path's arc function or the PathAnimation that's the problem but no matter the start angle ("0f" in example below), the animation always starts from the "east" and does one clockwise rotation? I'd like it to start from the top. Code: `void MoveButton() { var btn = FindViewById(Resource.Id.btn1); var path = new Path(); path.AddArc(-500, 0, 500, 1000, 0f, 360f); var anm = new PathAnimation(path); anm.Duration = 2000; anm.FillEnabled = true; anm.FillAfter = true; btn.StartAnimation(anm); }` – Cliffhanger Oct 11 '16 at 20:49
1

You can do a Frame by Frame animation. You can position the object step by step to create a curve. That will be of limited reuse, but you can do it.

Or you can write your own animation to create a subclass of TweenAnimation that can animate along a curve. If you're good with math and can understand bezier curves then that might be a straight forward option. Once you have that class you could easily animate across any curved path, but it's more work.

http://en.wikipedia.org/wiki/B%C3%A9zier_curve

Here's some Java code:

http://www.math.ubc.ca/~cass/gfx/bezier.html

chubbsondubs
  • 37,646
  • 24
  • 106
  • 138
0

You can create your own class like this:

public class BezierTranslateAnimation extends TranslateAnimation {

private int mFromXType    = ABSOLUTE;
private int mToXType      = ABSOLUTE;
private int mFromYType    = ABSOLUTE;
private int mToYType      = ABSOLUTE;
private float mFromXValue = 0.0f;
private float mToXValue   = 0.0f;
private float mFromYValue = 0.0f;
private float mToYValue   = 0.0f;
private float mFromXDelta;
private float mToXDelta;
private float mFromYDelta;
private float mToYDelta;
private float mBezierXDelta;
private float mBezierYDelta;

public BezierTranslateAnimation(float fromXDelta, float toXDelta,float fromYDelta, float toYDelta, float bezierXDelta, float bezierYDelta) {
     super(fromXDelta, toXDelta, fromYDelta, toYDelta);

      mFromXValue = fromXDelta;
      mToXValue   = toXDelta;
      mFromYValue = fromYDelta;
      mToYValue   = toYDelta;
      mFromXType  = ABSOLUTE;
      mToXType    = ABSOLUTE;
      mFromYType  = ABSOLUTE;
      mToYType    = ABSOLUTE;
      mBezierXDelta = bezierXDelta;
      mBezierYDelta = bezierYDelta;

}



@Override
protected void  applyTransformation(float interpolatedTime, Transformation t) {

    float dx=0,dy=0;

    if (mFromXValue != mToXValue) {

        dx  = (float) ((1.0-interpolatedTime)*(1.0-interpolatedTime)*mFromXValue + 2.0*interpolatedTime*(1.0-interpolatedTime)*mBezierXDelta + interpolatedTime*interpolatedTime*mToXValue);
    }

    if (mFromYValue != mToYValue) {

        dy  = (float) ((1.0-interpolatedTime)*(1.0-interpolatedTime)*mFromYValue + 2.0*interpolatedTime*(1.0-interpolatedTime)*mBezierYDelta + interpolatedTime*interpolatedTime*mToYValue);
    }

    t.getMatrix().setTranslate(dx, dy);

  }

}

Then use it with this signature:

BezierTranslateAnimation(float fromXDelta, float toXDelta,float fromYDelta, float toYDelta, float bezierXDelta, float bezierYDelta);
shi
  • 131
  • 3