动画通过点数组

时间:2016-03-22 15:29:38

标签: android animation android-animation

我确信有一种简单的方法可以做到这一点,但我被困住了。 假设我有一个点列表:

Point[] list = {pointA, pointB, pointC, ...}

我想通过每个点为ImageView制作动画 所以我尝试了这个:

id = 0;
AnimatorListenerAdapter animEnd = new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        id++;
        if(id != list.length) {
            iv.animate()
                .translationX(list[id].getX())
                .translationY(list[id].getY())
                .setDuration(200)
                .setListener(this);
        }
    }
};

iv.animate()
    .translationX(list[id].getX()).translationY(list[id].getY())
    .setDuration(200).setListener(animEnd);

它有效,但每个动画之间有一点延迟。

有什么想法吗?谢谢!

1 个答案:

答案 0 :(得分:9)

您可能会在动画步骤之间得到延迟,因为您总是在每个步骤之间的过渡时开始一个新动画。要克服这种情况,您有多种选择。

关键帧

Here你可以找到一种名为Keyframe Animation的技术,这是一种非常常见的动画技术,可能正是你想要的。

  

Keyframe对象包含一个时间/值对,可让您在动画的特定时间定义特定状态。每个关键帧也可以有自己的插值器来控制动画在前一个关键帧的时间和该关键帧的时间之间的间隔。

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000ms);

在您的情况下,您可以将list中的点映射到Keyframe个实例列表并...

Point[] list = {pointA, pointB, pointC, ...}
List<Keyframe> kfs = new ArrayList<Keyframe>();
foreach (Point p : points) {
  Keyframe kf = new Keyframe.ofFloat(p.x); // or what ever
  kfs.add(kf);
}

...稍后将这些关键帧传递给某些工厂方法以创建一些PropertyValuesHolder,例如具有以下签名的ofFloat

public static PropertyValuesHolder ofFloat (
    Property<?, Float> property, 
    float... values
)

第二个参数是一个变量参数列表,它也接受数组作为输入。因此,应该可以将kfs作为第二个参数传递给方法。

在你的情况下,我会制作以下方法,因为你正在为dalvik VM开发,你不能使用java8 lambda表达式:

// maps points to X/Y float values
List<Float> toArrayX(Point[] points) { ... }
List<Float> toArrayY(Point[] points) { ... }
// maps float values to Keyframes
List<Keyframe> toKeyframes(List<Float> floats) { ... }
void createAnimation(Point[] points) {
  List<Keyframe> xs = toKeyframes(toArrayX(points));
  PropertyValuesHolder phvX = PropertyValuesHolder
    .ofKeyframe("translationX", xs);

  List<Keyframe> ys = toKeyframes(toArrayY(points));
  PropertyValuesHolder phvY = PropertyValuesHolder
    .ofKeyframe("translationY", ys);

  linkPropertyValuesHolder(phvX);
  linkPropertyValuesHolder(phvY);
}
void linkPropertyValuesHolder(PropertyValuesHolder phv) {
  // setup target
  ObjectAnimator anim = ObjectAnimator
    .ofPropertyValuesHolder(target, phv)
  anim.setDuration(5000ms);
}

内插器

或者,您可以通过Interpolator实例指定点所给出的转换。

  

插值器定义动画的变化率。这允许加速,减速,重复等基本动画效果(alpha,缩放,平移,旋转)。

插值器将0.01.0之间的小数浮点映射到0.01.0之间的另一个小数浮点数。喜欢以下三个; LinearInterpolatorAccelerateDecelerateInterpolatorBounceInterpolator

来自here

图片

Path Interpolator

使用PathInterpolator s可以使用Path实例绘制arbritary插值器。绘制的路径将用于驱动动画。在您的情况下,您可以创建两个路径,一个用于x,另一个用于y转换。

但是,从路径构造插补器时要小心,因为

  

...... Path必须符合函数y = f(x)。

     

路径不得在x方向上有间隙,并且不得循环回自身,以便可以有两个点共享相同的x坐标。在垂直方向上有一条不相交的线是可以的:

因此,请查看以下从此处获取的代码段,创建一个有效路径,并可用作PathInterpolator构造函数的输入。

Path path = new Path();
path.lineTo(0.25f, 0.25f);
path.moveTo(0.25f, 0.5f);
path.lineTo(1f, 1f);

自定义插补器

当给定的插补器不够灵活时,您也可以实现Interpolator接口,然后从中创建一个新实例。界面非常狭窄,它只提供一个名为getInterpolation的方法,其签名如下。

public abstract float getInterpolation (float input)    

代码与XML

另一个最后一个选项是将所有动画配置移动到XML中,而不是将这些细节直接烘焙到代码的二进制分发中。但是,如果可能的话,每个给定的选项都需要通过XML管理不同的设置。

希望这会有所帮助,但它只是伪代码。我没有测试代码......因此没有正确性的保证。