Pergunta

Eu estou usando um RotateAnimation para girar uma imagem que eu estou usando como um spinner cíclica personalizada no Android. Aqui está o meu arquivo rotate_indefinitely.xml, que I colocado em 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" />    

Quando eu aplicar este a minha ImageView usando AndroidUtils.loadAnimation(), ele funciona muito bem!

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

O único problema é que a rotação da imagem parece fazer uma pausa no topo de cada ciclo.

Em outras palavras, a rotação da imagem 360 graus, faz uma breve pausa, depois gira 360 graus novamente, etc.

Eu suspeito que o problema é que a animação está usando um interpolador padrão como android:iterpolator="@android:anim/accelerate_interpolator" (AccelerateInterpolator), mas eu não sei como dizer não para interpolar a animação.

Como posso desligar a interpolação (se isso é realmente o problema) para fazer o meu ciclo de animação sem problemas?

Foi útil?

Solução

Você está certo sobre AccelerateInterpolator; você deve usar LinearInterpolator vez.

Você pode usar o built-in android.R.anim.linear_interpolator de seu arquivo XML animação com android:interpolator="@android:anim/linear_interpolator".

Ou você pode criar seu próprio arquivo de interpolação XML em seu projeto, por exemplo, nomeá-lo res/anim/linear_interpolator.xml:

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

E adicionar à sua XML animação:

android:interpolator="@anim/linear_interpolator"

Nota especial: Se a sua animação de rotação está dentro de um conjunto, definindo o interpolador não parece trabalho. Fazer o Gire a parte superior correções elemento de TI. (Isso irá poupar seu tempo.)

Outras dicas

Eu tive esse problema também, e tentou definir o interpolador linear em xml sem sucesso. A solução que funcionou para mim foi a de criar a animação como um RotateAnimation no código.

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

Isso funciona bem

<?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" />

Para inverter rotação:

<?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" />

Talvez, algo como isso vai ajudar:

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();

A propósito, você pode girar por mais de 360 ??como:

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

Tente usar toDegrees="359" desde 360 ??° e 0 ° são o mesmo.

Poda o <set>-Elemento que envolveu a <rotate>-Elemento resolve o problema!

Graças à Shalafi!

Portanto, o seu Rotation_ccw.xml deve loook assim:

<?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"
    />
ObjectAnimator.ofFloat(view, View.ROTATION, 0f, 360f).setDuration(300).start();

Tente isto.

Não importa o que eu tentei, eu não poderia chegar a este trabalho direito usando o código (e setRotation) para a animação rotação suave. O que eu acabei fazendo estava fazendo o grau muda tão pequena, que as pequenas pausas são imperceptíveis. Se você não precisa fazer muitas rotações, o tempo para executar este ciclo é insignificante. O efeito é uma rotação suave:

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

Como Hanry foi mencionado acima colocando forro iterpolator é bom. Mas se a rotação está dentro de um conjunto você deve colocar android:. ShareInterpolator = "false" para torná-lo suave

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

Se Sharedinterpolator não sendo falsa, o código acima dá falhas.

Rotação de objeto de programação.

// rotação no sentido horário:

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

rotação // sentido anti-horário:

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

Ver é objeto do seu ImageView ou outros widgets.

rotate.setRepeatCount (10);. uso de repetir sua rotação

500 é o tempo de duração da animação.

Se você estiver usando uma Animação conjunto como eu, você deve adicionar a interpolação dentro da tag set:

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

que funcionou para mim.

É possível que porque você ir de 0 a 360, você gastar um pouco mais tempo em 0/360 do que você está esperando? Talvez definir toDegrees a 359 ou 358.

Em Android, se você quiser animar um objeto e torná-lo mover um objeto de location1 para location2, as figuras de animação API fora os locais intermédios (interpolação) e depois filas para o segmento principal das operações de movimentação apropriados nos momentos apropriados utilizando um temporizador. Isso funciona bem, exceto que o segmento principal é normalmente usado para muitas outras coisas - pintura, abrir arquivos, respondendo ao usuário insumos etc. A fila de espera temporizador muitas vezes pode ser adiada. programas bem escritos sempre tentar fazer o maior número de operações quanto possível no fundo (não principais) tópicos, contudo, você não pode sempre evitar usar o segmento principal. Operações que exigem que você operar em um objeto de UI sempre tem que ser feito no segmento principal. Além disso, muitas APIs vai canalizar operações de volta para o segmento principal, como uma forma de thread-segurança.

As visualizações são todos desenhados no mesmo segmento GUI que também é usado para todos os interação do usuário.

Então, se você precisa de atualização GUI rapidamente ou se a prestação leva muito tempo e afeta a experiência do usuário, em seguida, usar SurfaceView.

Exemplo imagem de rotação:

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

atividade:

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

Tente usar mais de 360 ??para evitar a reinicialização.

Eu uso 3600 insted de 360 ??e esta multa funciona para mim:

<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%" />

Em Kotlin:

 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)
        })
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top