web-dev-qa-db-ja.com

Androidでスムーズな画像回転を作成するにはどうすればよいですか?

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にこれを適用すると、うまくいきます!

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

1つの問題は、画像の回転が各サイクルの先頭で一時停止するように見えることです。

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

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

アニメーションをスムーズに循環させるために、補間をオフにするにはどうすればよいですか(実際に問題がある場合)。

195
emmby

あなたはAccelerateInterpolatorについて正しいです。代わりにLinearInterpolatorを使用する必要があります。

Android.R.anim.linear_interpolatorを使用して、アニメーションXMLファイルの組み込みAndroid:interpolator="@Android:anim/linear_interpolator"を使用できます。

または、プロジェクトで独自のXML補間ファイルを作成できます。名前をres/anim/linear_interpolator.xml

<?xml version="1.0" encoding="utf-8"?>
<linearInterpolator xmlns:Android="http://schemas.Android.com/apk/res/Android" />

そして、アニメーションXMLに追加します。

Android:interpolator="@anim/linear_interpolator"

特記事項:回転アニメーションがセット内にある場合、補間の設定は機能しないようです。上部の要素を回転させると修正されます。 (これにより時間を節約できます。)

189
Bakhtiyor

私もこの問題を抱えていて、成功せずに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);
70
Rabs G

これはうまくいきます

<?xml version="1.0" encoding="UTF-8"?>
<rotate xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:duration="1600"
    Android:fromDegrees="0"
    Android:interpolator="@Android:anim/linear_interpolator"
    Android:pivotX="50%"
    Android:pivotY="50%"
    Android:repeatCount="infinite"
    Android:toDegrees="358" />

逆回転するには:

<?xml version="1.0" encoding="UTF-8"?>
<rotate xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:duration="1600"
    Android:fromDegrees="358"
    Android:interpolator="@Android:anim/linear_interpolator"
    Android:pivotX="50%"
    Android:pivotY="50%"
    Android:repeatCount="infinite"
    Android:toDegrees="0" />
32

たぶん、このような何かが役立ちます:

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        imageView.animate().rotationBy(360).withEndAction(this).setDuration(3000).setInterpolator(new LinearInterpolator()).start();
    }
};

imageView.animate().rotationBy(360).withEndAction(runnable).setDuration(3000).setInterpolator(new LinearInterpolator()).start();

ちなみに、次のように360度以上回転できます。

imageView.animate().rotationBy(10000)...
30

360°と0°は同じなので、toDegrees="359"を使用してみてください。

28

<set>- Elementをラップした<rotate>- 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"
    />
6
ObjectAnimator.ofFloat(view, View.ROTATION, 0f, 360f).setDuration(300).start();

これを試して。

5
Ashraf Rahman

ハンリーが前述したように、ライナーインターポレーターを置くことは問題ありません。ただし、回転がセット内にある場合は、スムーズにするためにAndroid:shareInterpolator = "false"を配置する必要があります。

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:Android="http://schemas.Android.com/apk/res/Android"
**Android:shareInterpolator="false"**
>
<rotate
    Android:interpolator="@Android:anim/linear_interpolator"
    Android:duration="300"
    Android:fillAfter="true"
    Android:repeatCount="10"
    Android:repeatMode="restart"
    Android:fromDegrees="0"
    Android:toDegrees="360"
    Android:pivotX="50%"
    Android:pivotY="50%" />
<scale xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:interpolator="@Android:anim/linear_interpolator"
    Android:duration="3000"
    Android:fillAfter="true"
    Android:pivotX="50%"
    Android:pivotY="50%"
    Android:fromXScale="1.0"
    Android:fromYScale="1.0"
    Android:toXScale="0"
    Android:toYScale="0" />
</set>

Sharedinterpolatorがfalseでない場合、上記のコードはグリッチを与えます。

3
Rahul Agrawal

何を試しても、スムーズな回転アニメーションのためのコード(および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);
        }
3
ununiform

プログラムで回転オブジェクト。

//時計回りの回転:

    public void rorate_Clockwise(View view) {
        ObjectAnimator rotate = ObjectAnimator.ofFloat(view, "rotation", 180f, 0f);
//        rotate.setRepeatCount(10);
        rotate.setDuration(500);
        rotate.start();
    }

//反時計回りの回転:

 public void rorate_AntiClockwise(View view) {
        ObjectAnimator rotate = ObjectAnimator.ofFloat(view, "rotation", 0f, 180f);
//        rotate.setRepeatCount(10);
        rotate.setDuration(500);
        rotate.start();
    } 

viewは、ImageViewまたは他のウィジェットのオブジェクトです。

rotate.setRepeatCount(10);回転を繰り返すために使用します。

5はアニメーション時間です。

3
Geet Thakur

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

<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>

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

2
Kokusho

0から360に移動するため、0/360で予想よりも少し時間がかかる可能性はありますか?おそらく、Degreesを359または358に設定します。

1
William Rose

コトリンで:

 ivBall.setOnClickListener(View.OnClickListener {

            //Animate using XML
            // val rotateAnimation = AnimationUtils.loadAnimation(activity, R.anim.rotate_indefinitely)

            //OR using Code
            val rotateAnimation = RotateAnimation(
                    0f, 359f,
                    Animation.RELATIVE_TO_SELF, 0.5f,
                    Animation.RELATIVE_TO_SELF, 0.5f

            )
            rotateAnimation.duration = 300
            rotateAnimation.repeatCount = 2

            //Either way you can add Listener like this
            rotateAnimation.setAnimationListener(object : Animation.AnimationListener {

                override fun onAnimationStart(animation: Animation?) {
                }

                override fun onAnimationRepeat(animation: Animation?) {
                }

                override fun onAnimationEnd(animation: Animation?) {

                    val Rand = Random()
                    val ballHit = Rand.nextInt(50) + 1
                    Toast.makeText(context, "ballHit : " + ballHit, Toast.LENGTH_SHORT).show()
                }
            })

            ivBall.startAnimation(rotateAnimation)
        })
0
Hitesh Sahu

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));
    }
}
0
phnmnn

再起動を避けるために、360以上を使用してみてください。

私は360ではなく3600を使用していますが、これは私にとってうまくいきます:

<rotate xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:fromDegrees="0"
    Android:toDegrees="3600"
    Android:interpolator="@Android:anim/linear_interpolator"
    Android:repeatCount="infinite"
    Android:duration="8000"
    Android:pivotX="50%"
    Android:pivotY="50%" />
0
fisher3421