【问题标题】:Custom animation in AndroidAndroid中的自定义动画
【发布时间】:2019-12-01 10:44:42
【问题描述】:

我写了一个自定义View。现在我想在用户触摸它时做一些自定义动画。

当我说自定义时,我的意思是我基​​本上想自己渲染每一帧,并且使用像here 所述的“预定义”动画。

实现这一点的正确方法是什么?

【问题讨论】:

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

标签: android animation


【解决方案1】:

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

一般:

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

这是一个例子(我正在使用这个类来改变我的Bitmap的sset。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 Animator 框架(或兼容性实现 - 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();
    }

}

【讨论】:

    【解决方案2】:
    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());
    

    【讨论】:

    • 看起来不错。以编程方式呈现这些可绘制对象是否可行? (动画取决于用户点击的位置...)
    • 可以通过 setBackgroundResource 将 'AnimationDrawable' 'animation' 设置为 View 背景。您还可以找到简单的方法来绝对定位它与覆盖。可能取决于用户点击的位置! (在按钮上?表面视图?图像?列表视图?)
    【解决方案3】:

    我假设您将每个帧创建为位图,然后将其直接传递给动画,而不是从资源中获取 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 动画上花费太多资源......如果有一种“重复”安排重绘并按需渲染帧的好方法,我会没有这个问题。
    • 好吧,如果你使用 Opengl,它们应该都能处理 30fps 没问题。如果你正在做任何具有图形挑战性的事情,你应该这样做。 Canvas 和 GL 之间存在巨大的性能差异。
    【解决方案4】:

    用另一个 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"/>
    

    【讨论】:

      【解决方案5】:

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

      1. alpha - 元素的动画透明度
      2. 翻译 - 元素的动画位置
      3. 缩放 - 元素的动画大小
      4. rotate - 元素的动画旋转

      这是一个blog post,它详细解释了它们中的每一个。

      创建动画后,只需使用以下代码将该自定义动画添加到视图。

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

      【讨论】:

      • 我想你错过了我问题的第二段。
      【解决方案6】:

      除了在 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 将动画设置为 View 背景。

      如果您想做一些更复杂的事情,请查看Canvas 类。请参阅有关如何draw with Canvas 的简要介绍。

      【讨论】:

      • 他想在程序内部渲染每一帧。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 2016-03-28
      • 2012-08-12
      • 1970-01-01
      相关资源
      最近更新 更多