【问题标题】:Android: onDraw constantly called or animation snaps back to original positionAndroid:onDraw 不断调用或动画快速回到原始位置
【发布时间】:2012-01-16 06:35:47
【问题描述】:

所以,我的问题有点类似于这两个问题:

Custom View onDraw is constantly called

android: onDraw is called constantly

我有一个扩展 ImageView 的自定义类,我将 RotateAnimation 应用到该类。动画使用输入的 x 和 y 坐标执行从上一个角度到下一个角度的旋转,因此用户可以根据需要将 ImageView 从 -360 度旋转到 360 度。当我将此代码用于 onDraw() 时,屏幕上的一切看起来都很完美(动画设置如下面的代码):

@Override
protected void onDraw(Canvas canvas) {
    Log.d(TAG, "It is drawn again!");
    this.setAnimation(anim);
    super.onDraw(canvas);
}

问题在于,与提到的其他帖子中的方式相同,动画调用 onDraw 调用动画等等,可能是通过 RotateAnimation 类中的 invalidate()。这是否正确观察?输出非常完美,因为 ImageView 始终保持在当前计算的角度,但动画计算因此继续进行,消耗大量功率和容量。

为了解决这个问题,我尝试在计算动画参数的方法中移动 this.setAnimation(anim)(请忽略 isClockWise()、calculateAngleToMove() 和其他非 android 内容,它们按预期工作) :

private void turnWheel(){
    float angle = 0;

    if ( isClockWise() ){
        angle = calculateAngleToMove();         
        anim = new RotateAnimation(current_angle, angle, center_x, center_y);
        anim.setFillAfter(true);
        anim.setFillEnabled(true);
        current_angle += angle; 
    }
    else{
        angle = - calculateAngleToMove();
        anim = new RotateAnimation(current_angle, angle, center_x, center_y);
        anim.setFillAfter(true);
        anim.setFillEnabled(true);
        current_angle += angle;
    }

    if ( current_angle > 360 ){
        current_angle = current_angle - 360;
    }
    if ( current_angle < -360 ){
        current_angle = current_angle + 360;
    }

    this.setAnimation(anim);
    this.invalidate();  //Calls onDraw()

}

这解决了 onDraw 不断被调用的问题,但它产生了另一个问题:当用户按下、按住和转动 ImageView 时,它会在零角度和当前角度之间来回切换。当用户随后放开 ImageView 时,它会回弹到零角度。希望始终以变量 current_angle 旋转 ImageView,即使在用户不提供输入时也是如此。

我尝试过不同版本的 anim.setFillAfter(true)、anim.setFillEnabled(true)、invalidate() 和 this.startAnimation(anim),但它们似乎对这个问题没有任何效果。

调用 this.setAnimation(anim) 的最佳位置在哪里?

【问题讨论】:

    标签: android android-animation android-view


    【解决方案1】:

    我可能建议不要使用Animation 框架将静态转换应用于视图,这样您就不必在每次应用新的Animation 时处理重置引起的问题。

    如果您希望旋转的内容仅包含图像,请考虑将您的图像包装在 RotateDrawable 中,并将其设置为您的 ImageView 的内容。有了这个,您可以通过设置它的级别值来控制可绘制对象的旋转方式(Drawable.setLevel()ImageView.setImageLevel() 应该可以做到这一点)并且转换将保持不变。如果您需要在一段时间内自动执行动画,您可以简单地调用 Handler 中的关卡设置代码,该代码会不时发布更新。

    另一种选择是创建自定义ViewGroup 并使用getChildStaticTransformation() 方法将旋转应用到任何子视图(确保启用它或覆盖已经启用它的子类)。 Transformation 也是 Animation 框架用来修改视图外观的。在这种情况下,您可能仍需要在用户输入更改时调用invalidate() 以强制重新绘制。如果您想定期自动更改更改,同样的 Handler 规则将适用。

    RotateDrawable 示例

    假设您要旋转的图像位于 res/drawable/wheel.png,在 res/drawable/wheel_rotate.xml 创建一个简单的 XML 文件:

    <rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/wheel"
        android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="50%"
        android:pivotY="50%" />
    

    将您的图像包装成RotateDrawable。然后,在您的 Java 代码集中,可绘制为 ImageView 的内容:

    ImageView wheel;
    //You only do this once
    wheel.setImageResource(R.drawable.wheel_rotate);
    
    //Adjust the progress any time you need to by adjusting the drawable's level
    wheel.setImageLevel(500);
    

    默认情况下,级别范围为 0 到 10,000。因此映射到 0 级 = fromDegrees 和 10,000 级 = toDegrees。

    HTH

    【讨论】:

    • 使用 RotateDrawable 似乎是一个很好的解决方案,但我似乎无法弄清楚如何以编程方式执行此操作。你能提供或指出一个例子吗?
    • 提供的简单示例应该为您提供所需的所有挂钩。
    猜你喜欢
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 2015-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-16
    相关资源
    最近更新 更多