Android'de düzgün görüntü döndürme nasıl yapılır?


217

Ben kullanıyorum RotateAnimationben Android'de bir özel döngüsel spinner olarak kullanıyorum o görüntüyü döndürmek için. İşte benim rotate_indefinitely.xmlyerleştirdiğim dosya 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" />    

Ben benim için bu uyguladığınızda ImageViewkullanarak AndroidUtils.loadAnimation(), o inşaat büyük!

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

Tek sorun, görüntü döndürmenin her döngünün üstünde durakladığı görülüyor.

Başka bir deyişle, görüntü 360 derece döner, kısa bir süre duraklar, sonra tekrar 360 derece döner vb.

Sorunun, animasyonun android:iterpolator="@android:anim/accelerate_interpolator"( AccelerateInterpolator) gibi varsayılan bir enterpolatör kullandığından şüpheleniyorum , ancak animasyona enterpolasyon yapmamasını nasıl söyleyeceğimi bilmiyorum.

Animasyon döngümü sorunsuz bir şekilde yapmak için enterpolasyonu (gerçekten sorun varsa) nasıl kapatabilirim?

Yanıtlar:


199

AccelerateInterpolator konusunda haklısınız; bunun yerine LinearInterpolator kullanmalısınız.

android.R.anim.linear_interpolatorAnimasyon XML dosyanızdaki yerleşik ile birlikte kullanabilirsiniz android:interpolator="@android:anim/linear_interpolator".

Veya projenizde kendi XML enterpolasyon dosyanızı oluşturabilirsiniz, örneğin adlandırın res/anim/linear_interpolator.xml:

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

Ve animasyon XML'inize ekleyin:

android:interpolator="@anim/linear_interpolator"

Özel Not: Döndürme animasyonunuz bir kümenin içindeyse, enterpolatörün ayarlanması işe yaramaz gibi görünür. Üst elemanın döndürülmesi onu düzeltir. (bu size zaman kazandıracaktır.)


1
Bunun nedeni enterpolatörün yanlış yazılmasıdır ("n" yok). Kendiniz yapmak zorunda değilsiniz
Kingpin

25
Doğrusal da dahil olmak üzere mevcut her enterpolatörü denedim ve hala her döngünün başında bu küçük "aksama" alıyorum.
Adam Rabung

11
Döndürme animasyonunuz bir kümenin içindeyse, enterpolatörü ayarlamak işe yaramıyor gibi görünüyor. Üst elemanı döndürmek
düzeltiyor

Hey, eğer gerçekten her animasyon arasında küçük bir "duraklama" olmadan accelerate_decelerate_interpolator kullanmak isterseniz ne olacak?
agonist_

90

Ben de bu sorunu vardı ve doğrusal interpolator xml başarılı olmadan ayarlamak için çalıştı. Benim için çalışan çözüm, animasyonu kodda bir RotateAnimation olarak oluşturmaktı.

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

9
animasyonun sonunda yönlendirmede kalmasını istiyorsanız, ekleyinrotate.setFillAfter(true);
Fonix

4
animasyonun kalıcı olarak kalmasını istiyorsanız, ekleyinrotate.setRepeatCount(Animation.INFINITE);
ahmednabil88

38

Bu iyi çalışıyor

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

Döndürmeyi tersine çevirmek için:

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

5
Tersine, sadece yineleme sayısı 2 var ve android ayarlamak: repeatMode = "ters" - iki farklı XML dosyalarına gerek yok.
RoundSparrow hilltx

3
neden 358 ve 359 veya 360 değil?
Mart'ta behelit

Bu dosyayı kaynaklara nereye ekleyebilirim? Animasyon bunun için ayrı bir paket mi?
abggcv

30

Belki böyle bir şey yardımcı olacaktır:

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

Bu arada, 360'tan fazla döndürülebilir:

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

Mükemmel çalışıyor, imageView.clearAnimation () çalıştırılabilirliği de temizleyecek mi?
XcodeNOOB

Başlangıç ​​animasyonu için iyi çalışıyor, ancak başladıktan sonra runnable imageView.clearAnimation () tarafından temizlenmedi, dokunmatik dinleyici etkinliğinde kullandım
Abhijit Jagtap

Bu runnable'ları bağımsız olarak durduramıyorum
Pants

@Bir durumla EndAction (bu) ile arayabileceğiniz kişiler. Durum yanlışsa, EndAction (this) ile çağrılmaz ve animasyon durmalıdır
Vitaly Zinchenko


19
ObjectAnimator.ofFloat(view, View.ROTATION, 0f, 360f).setDuration(300).start();

Bunu dene.


8

Nesneyi programlı olarak döndürün.

// Saat yönünde dönüş :

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

// Saat yönünün tersine döndürme:

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

view , ImageView veya diğer widget'larınızın nesnesidir.

rotate.setRepeatCount (10); rotasyonunuzu tekrarlamak için kullanın.

500 , animasyon zaman sürenizdir.


6

Budama <set>-eleman sarılı olduğu <rotate>-eleman çözdüğü sorunu!

Shalafi'ye teşekkürler!

Bu nedenle Rotation_ccw.xml dosyanız şöyle görünmelidir:

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

3

Ne denediğim önemli değil, düzgün dönüş animasyonu için kod (ve setRotation) kullanarak doğru çalışmak için alamadım. Yaptığım şey derece değişikliklerini o kadar küçük yapmaktı ki, küçük duraklamalar farkedilemezdi. Çok fazla dönüş yapmanız gerekmiyorsa, bu döngüyü yürütme süresi göz ardı edilebilir. Etki düzgün bir dönüştür:

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

"animasyon" değişken bildirimi nerede?
Rishabh Saxena

3

Hanry yukarıda belirtildiği gibi astar koymak iterpolator iyidir. Ancak döndürme bir kümenin içindeyse, bunu pürüzsüz hale getirmek için android: shareInterpolator = "false" koymalısınız.

<?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 yanlış değilse, yukarıdaki kod hata verir.


3

Benim gibi bir set Animasyon kullanıyorsanız, enterpolasyonu set etiketinin içine eklemelisiniz:

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

Bu benim için çalıştı.


3

Kotlin'de:

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

1

0'dan 360'a gittiğiniz için 0/360'ta beklediğinizden biraz daha fazla zaman geçirmeniz mümkün mü? Belki Dereceleri 359 veya 358 olarak ayarlayın.


1
Büyük teori. Emin değilim çünkü hızlanma / yavaşlama oldukça pürüzsüz ve kasıtlı görünüyor. Her ne kadar dereceleri 358'e düşürmeyi denesem ve davranışta fark edilebilir bir değişiklik olmadı.
emmby

1

Yeniden başlatmayı önlemek için 360'tan fazla kullanmaya çalışın.

360 in 3600 insted kullanın ve bu benim için iyi çalışıyor:

<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

Android'de, bir nesneyi canlandırmak ve nesneyi konum1'den konum2'ye taşımak istiyorsanız, animasyon API'sı ara konumları (ara doldurma) anlar ve ardından bir zamanlayıcı kullanarak uygun hareket işlemlerini uygun zamanlarda sıralar . Bu, ana iş parçacığının genellikle diğer birçok şey için kullanılması dışında işe yarar - boyama, dosyaları açma, kullanıcı girişlerine yanıt verme vb. İyi yazılmış programlar her zaman arka plan (ana olmayan) iş parçacıklarında mümkün olduğunca çok işlem yapmaya çalışır, ancak her zaman ana iş parçacığını kullanmaktan kaçınamazsınız. Bir UI nesnesinde çalışmanızı gerektiren işlemlerin her zaman ana iş parçacığında yapılması gerekir. Ayrıca, birçok API, bir iş parçacığı güvenliği biçimi olarak işlemleri ana iş parçacığına geri yönlendirir.

Görünümlerin tümü, tüm kullanıcı etkileşimi için de kullanılan aynı GUI iş parçacığında çizilir.

Dolayısıyla, GUI'yi hızlı bir şekilde güncellemeniz gerekiyorsa veya oluşturma işlemi çok fazla zaman alıyorsa ve kullanıcı deneyimini etkiliyorsa SurfaceView kullanın.

Döndürme görüntüsü örneği:

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

aktivite:

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
private fun rotateTheView(view: View?, startAngle: Float, endAngle: Float) {
    val rotate = ObjectAnimator.ofFloat(view, "rotation", startAngle, endAngle)
    //rotate.setRepeatCount(10);
    rotate.duration = 400
    rotate.start()
}

1
Bu kod soruya bir çözüm sunabilse de, neden / nasıl çalıştığına ilişkin bağlam eklemek daha iyidir. Bu, gelecekteki kullanıcıların bu bilgileri öğrenmelerine ve kendi kodlarına uygulamalarına yardımcı olabilir. Kod açıklandığında, kullanıcılardan upvotes şeklinde olumlu geri bildirimleriniz de olabilir.
borchvm
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.