实现弯曲动画的问题

时间:2011-07-27 18:45:56

标签: android android-animation

  

可能重复:
  Android, move bitmap along a path?

我想通过曲线路径移动图像。它可能在Android中吗?我搜索了很多,但我只能找到关于比例,旋转和翻译动画。所以任何人有任何想法请帮助。它可能在Android?

4 个答案:

答案 0 :(得分:9)

下面是功能完备的代码,它将沿着由三个点定义的弯曲路径进行动画处理。 Point只是一个包含x值和y值的类(尽管您可以轻松地将其扩展为更多维度)。

所有m个变量都来自TranslateAnimation并以类似的方式使用,因此如果没有意义,您应该能够相对地比较它与TranslateAnimation代码。

初始化中对resolveSize的调用意味着您可以使用任何动画类型(ABSOLUTE,RELATIVE_TO_SELF,RELATIVE_TO_PARENT)指定弧的起点,终点和半径,就像使用普通TranslateAnimation一样。

calcBezier计算直接取自Wikipedia的二次贝塞尔曲线。贝塞尔曲线应该允许平滑缩放,并且在图形中很常见(并且也在Android的Path类中使用)。

实际移动发生在applyTransformation中。 interpolatedTime给出一个介于0和1之间的值,该值根据提供的插值器非线性增加。 dx和dy是给定时间沿曲线的实际x和y点。

此类的唯一限制是y中的最大变化始终发生在曲线的中心(请参阅初始化中的middleX计算)。但是,如果您想要非对称曲线,则很容易修改,例如,沿曲线给出特定点,在该曲线处应出现高点。

查看TranslateAnimation的android代码特别有用。请参阅: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);
}
}

答案 1 :(得分:5)

它的灵感来自Monkeyless的回答。 我创建了一个Animation的子类,使用PathMeasure来计算翻译。 您可以使用Path创建一个新的PathAnimation,并像使用任何其他动画一样使用它。

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]);
}
}

答案 2 :(得分:1)

您可以执行逐帧动画。您可以逐步定位对象以创建曲线。这将是有限的重用,但你可以做到。

或者您可以编写自己的动画来创建TweenAnimation的子类,该子类可以沿曲线设置动画。如果你对数学很好并且能够理解贝塞尔曲线那么这可能是一个直接的选择。一旦你有了这个课程,你就可以轻松地在任何弯曲的路径上制作动画,但这样做更有效。

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

这是一些Java代码:

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

答案 3 :(得分:0)

您可以像这样创建自己的类:

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);

  }

}

然后使用此签名:

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