Androidで滑らかな画像ローテーションを作成する方法は?


Answers

私はこの問題も抱えていて、xmlの線形補間器を成功せずに設定しようとしました。 私のために働いた解決策は、アニメーションをコードでRotateAnimationとして作成することでした。

RotateAnimation rotate = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(5000);
rotate.setInterpolator(new LinearInterpolator());

ImageView image= (ImageView) findViewById(R.id.imageView);

image.startAnimation(rotate);
Question

私はRotateAnimationを使用して、Androidでカスタムの循環スピンとして使用している画像を回転させています。 rotate_indefinitely.xmlファイルはres/anim/に置いてあります:

<?xml version="1.0" encoding="UTF-8"?>
<rotate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="infinite"
    android:duration="1200" />    

これをAndroidUtils.loadAnimation()を使用してImageViewに適用すると、 AndroidUtils.loadAnimation()ます!

spinner.startAnimation( 
    AnimationUtils.loadAnimation(activity, R.anim.rotate_indefinitely) );

1つの問題は、画像の回転が各サイクルの最上部で停止しているように見えることです。

つまり、画像は360度回転し、一時停止してから360度回転します。

アニメーションがandroid:iterpolator="@android:anim/accelerate_interpolator"AccelerateInterpolator )のようなデフォルトのインターポレータを使用しているという問題があると思われますが、アニメーションを補間しないように指示する方法はわかりません。

私のアニメーションサイクルを円滑にするために補間を無効にするにはどうしたらいいですか?




360°と0°が同じなのでtoDegrees="359"を使ってみてください。




私のようなアニメーションセットを使用している場合、セットタグ内に補間を追加する必要があります:

<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator">

 <rotate
    android:duration="5000"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="infinite"
    android:startOffset="0"
    android:toDegrees="360" />

 <alpha
    android:duration="200"
    android:fromAlpha="0.7"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:toAlpha="1.0" />

</set>

それは私のために働いた。




Androidでは、オブジェクトをアニメーション化してオブジェクトをlocation1からlocation2に移動させる場合、アニメーションAPIは中間の位置(トゥイーン)を特定してから、タイマーを使用して適切な時間に適切な移動操作をメインスレッドにキューイングします。 これは、メインスレッドが通常、ペイント、ファイルのオープン、ユーザー入力への応答など、他の多くのものに使用されることを除いて、うまく動作します。キューに入れられたタイマーはしばしば遅れることがあります。 よく書かれたプログラムは、バックグラウンド(非メイン)スレッドで可能な限り多くの操作を実行しようとしますが、メインスレッドの使用を常に避けることはできません。 UIオブジェクトを操作する必要がある操作は、常にメインスレッド上で行う必要があります。 また、多くのAPIは、スレッド安全性の一形態として、メインスレッドに操作を戻します。

ビューはすべて同じGUIスレッド上に描画され、すべてのユーザー操作にも使用されます。

したがって、GUIをすばやく更新する必要がある場合、またはレンダリングに時間がかかりすぎてユーザーエクスペリエンスが低下する場合は、SurfaceViewを使用してください。

回転イメージの例:

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
    private DrawThread drawThread;

    public MySurfaceView(Context context) {
        super(context);
        getHolder().addCallback(this);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {   
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        drawThread = new DrawThread(getHolder(), getResources());
        drawThread.setRunning(true);
        drawThread.start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        drawThread.setRunning(false);
        while (retry) {
            try {
                drawThread.join();
                retry = false;
            } catch (InterruptedException e) {
            }
        }
    }
}


class DrawThread extends Thread{
    private boolean runFlag = false;
    private SurfaceHolder surfaceHolder;
    private Bitmap picture;
    private Matrix matrix;
    private long prevTime;

    public DrawThread(SurfaceHolder surfaceHolder, Resources resources){
        this.surfaceHolder = surfaceHolder;

        picture = BitmapFactory.decodeResource(resources, R.drawable.icon);

        matrix = new Matrix();
        matrix.postScale(3.0f, 3.0f);
        matrix.postTranslate(100.0f, 100.0f);

        prevTime = System.currentTimeMillis();
    }

    public void setRunning(boolean run) {
        runFlag = run;
    }

    @Override
    public void run() {
        Canvas canvas;
        while (runFlag) {
            long now = System.currentTimeMillis();
            long elapsedTime = now - prevTime;
            if (elapsedTime > 30){

                prevTime = now;
                matrix.preRotate(2.0f, picture.getWidth() / 2, picture.getHeight() / 2);
            }
            canvas = null;
            try {
                canvas = surfaceHolder.lockCanvas(null);
                synchronized (surfaceHolder) {
                    canvas.drawColor(Color.BLACK);
                    canvas.drawBitmap(picture, matrix, null);
                }
            } 
            finally {
                if (canvas != null) {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
        }
    }
}

アクティビティ:

public class SurfaceViewActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MySurfaceView(this));
    }
}



私が何を試しても、円滑な回転アニメーションのためにコード(およびsetRotation)を使用してこれを正しく機能させることができませんでした。 私がやったことは、程度の変化を小さくすること、小さな休止は気づかないことでした。 あまり回転させる必要がない場合、このループを実行する時間は無視してかまいません。 効果は滑らかな回転です:

        float lastDegree = 0.0f;
        float increment = 4.0f;
        long moveDuration = 10;
        for(int a = 0; a < 150; a++)
        {
            rAnim = new RotateAnimation(lastDegree, (increment * (float)a),  Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            rAnim.setDuration(moveDuration);
            rAnim.setStartOffset(moveDuration * a);
            lastDegree = (increment * (float)a);
            ((AnimationSet) animation).addAnimation(rAnim);
        }



<rotate> -Elementをラップした<set> -Elementをプルーニングすると、問題は解決します。

Shalafiに感謝します!

したがって、あなたのRotation_ccw.xmlは次のようになっています:

<?xml version="1.0" encoding="utf-8"?>

<rotate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:toDegrees="-360"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="2000"
    android:fillAfter="false"
    android:startOffset="0"
    android:repeatCount="infinite"
    android:interpolator="@android:anim/linear_interpolator"
    />





Links