安卓中的自定义动画

26

我编写了一个自定义的 View,现在当用户触摸它时,我想做一点自定义动画。

所谓自定义,我基本上希望自己渲染每一帧,并且使用像这里描述的“预定义”动画。

如何正确实现这个?


@AjitSingh,那篇文章描述了标准动画(旋转、平移等)。这里我在询问的是自定义动画。 - aioobe
6个回答

23

创建自定义动画的最灵活(也相当简单)的方法是扩展Animation类。

一般而言:

  1. 使用setDuration()方法设置动画持续时间。
  2. 可选择使用setInterpolator()方法为动画设置插值器,例如可以使用LinearInterpolatorAccelerateInterpolator等。
  3. 重写applyTransformation方法。其中我们感兴趣的是interpolatedTime变量,它在0.0和1.0之间变化,并表示您的动画进度。

以下是一个示例(我使用此类来更改Bitmap的偏移量。 Bitmap本身是在draw方法中绘制的):

public class SlideAnimation extends Animation {

    private static final float SPEED = 0.5f;

    private float mStart;
    private float mEnd;

    public SlideAnimation(float fromX, float toX) {
        mStart = fromX;
        mEnd = toX;

        setInterpolator(new LinearInterpolator());

        float duration = Math.abs(mEnd - mStart) / SPEED;
        setDuration((long) duration);
    }

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

        float offset = (mEnd - mStart) * interpolatedTime + mStart;
        mOffset = (int) offset;
        postInvalidate();
    }

}

你也可以使用 Transformation#getMatrix() 来修改 View

更新

如果你在使用Android动画框架(或兼容实现 - NineOldAndroids),你只需要为你的自定义 View 属性声明setter和getter并直接对其进行动画。以下是另一个示例:

public class MyView extends View {

    private int propertyName = 50;

    /* your code */

    public int getPropertyName() {
        return propertyName;
    }

    public void setPropertyName(int propertyName) {
        this.propertyName = propertyName;
    }

    /*
    There is no need to declare method for your animation, you 
    can, of course, freely do it outside of this class. I'm including code
    here just for simplicity of answer.
    */
    public void animateProperty() {
        ObjectAnimator.ofInt(this, "propertyName", 123).start();
    }

}

3
Animation animation = new AnimationDrawable();
animation.addFrame(getResources().getDrawable(R.drawable.exp1), 50);
animation.addFrame(getResources().getDrawable(R.drawable.exp2), 50);
animation.addFrame(getResources().getDrawable(R.drawable.exp3), 50);
animation.addFrame(getResources().getDrawable(R.drawable.exp4), 50);
animation.addFrame(getResources().getDrawable(R.drawable.exp5), 50);
animation.addFrame(getResources().getDrawable(R.drawable.exp6), 50);

这是我在onCreate()中使用的代码,用于生成自定义逐帧动画。

之后,我需要在UI线程内启动动画。因此,我使用了Runnable。

class Starter implements Runnable {
    public void run() {
        animation.stop();
        animation.start();
    }
}

我通过ImageView的.post()方法在onClick()中启动了该Runnable:

((ImageView) findViewById(R.id.ImageToAnimateOnClicking)).post(new Starter());

看起来不错。在程序中动态渲染这些可绘制对象是否可行?(动画取决于用户的点击位置...) - aioobe
“AnimationDrawable”动画可以通过setBackgroundResource设置为视图背景。您还可以找到轻松的方法使用覆盖层绝对定位它。这可能取决于用户点击的位置!(在按钮上?SurfaceView?图像?ListView?) - Cory Trese

1

我假设您将每个帧都创建为位图,然后直接将其传递给动画,而不是从资源中获取Drawable。

Bitmap bm = Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_888);
Canvas c = new Canvas(bm);
.... Draw to bitmap
animation.addFrame(bm,50)
.... repeat for all frames you wish to add.

很遗憾,我无法提前知道设备可以处理的FPS数量。如果它只能处理5 FPS,那么我就不应该在渲染20 FPS动画上花费太多资源...如果有一种好的方法可以“重复”安排重新绘制,并按需呈现帧,那么我就不会有这个问题了。 - aioobe
1
如果你使用OpenGL,它们都应该能够轻松处理30fps。如果你正在进行任何图形挑战,那么你应该这样做。Canvas和GL之间存在巨大的性能差异。 - HaMMeReD

1

当用另一个Fragment替换Fragment时,我的自定义动画:

getSupportFragmentManager().beginTransaction()
                    .setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left)
                    .replace(currentFragment.getId(), newFragment).commit();
            currentFragment = newFragment;

XML slide_in_right:

<translate android:fromXDelta="100%p" android:toXDelta="0"
    android:duration="1000"/>

XML slide_out_left:

<translate android:fromXDelta="0" android:toXDelta="-100%p"
    android:duration="1000"/>

0

您可以为自定义视图添加四种类型的动画。

  1. alpha - 动画元素透明度
  2. translate - 动画元素位置
  3. scale - 动画元素大小
  4. rotate - 动画元素旋转

这篇博客文章详细介绍了它们每一种的用法。

当您完成创建动画后,只需使用以下代码将该自定义动画添加到视图中即可。

findById(R.id.element).startAnimation(AnimationUtils.loadAnimation(this, R.anim.custom_animation));

我认为你错过了我问题中的第二段。 - aioobe

-1
除了在 XML 中定义补间动画之外,您还可以定义逐帧动画(存储在 res/drawable 中)。
<animation-list
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:oneshot="true"
>
    <item android:drawable="@drawable/frame1" android:duration="300" />
    <item android:drawable="@drawable/frame2" android:duration="300" />
    <item android:drawable="@drawable/frame3" android:duration="300" />
</animation-list>

通过setBackgroundResource将动画设置为视图背景。

如果您想做更复杂的事情,请查看Canvas类。请参阅有关如何使用Canvas绘制的简要介绍。


1
他想在程序内渲染每一帧。 - dacwe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接