动画通过点数组

La *_*sse 11 animation android android-animation

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

Point[] list = {pointA, pointB, pointC, ...}
Run Code Online (Sandbox Code Playgroud)

我想通过每个点动画一个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);
Run Code Online (Sandbox Code Playgroud)

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

任何的想法?谢谢 !

isa*_*s-b 9

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

关键帧

在这里你可以找到一种名为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);
Run Code Online (Sandbox Code Playgroud)

在您的情况下,您可以将您的点映射listKeyframe实例列表并...

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);
}
Run Code Online (Sandbox Code Playgroud)

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

public static PropertyValuesHolder ofFloat (
    Property<?, Float> property, 
    float... values
)
Run Code Online (Sandbox Code Playgroud)

第二个参数是一个变量参数列表,它也接受数组作为输入.因此,应该可以以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);
}
Run Code Online (Sandbox Code Playgroud)

插值

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

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

内插器之间映射的分数浮子0.01.0另一分数浮子之间0.01.0.喜欢以下三个; LinearInterpolator,AccelerateDecelerateInterpolatorBounceInterpolator:

来自这里的图片

路径插补器

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

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

...路径必须符合函数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);
Run Code Online (Sandbox Code Playgroud)

自定义插补器

当给定的插补器不够灵活时,您也可以实现Interpolator接口并在之后创建一个新的实例.接口非常窄,它只提供一个getInterpolation使用以下签名调用的方法.

public abstract float getInterpolation (float input)    
Run Code Online (Sandbox Code Playgroud)

代码与XML

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

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