Rotation de l'image. Liste d'Animation ou rotation animée? (Android)

je veux créer une image de progression rotative, et me demande Quelle est la meilleure façon de procéder. Je peux le faire fonctionner avec une liste d'animation avec par exemple 12 images changeant tous les 100ms. Cela fonctionne très bien, mais il est assez fastidieux de créer 12 images ou pour chaque taille et résolution:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
<item android:drawable="@drawable/ic_loading_grey_on_black_01" android:duration="100" />
<item android:drawable="@drawable/ic_loading_grey_on_black_02" android:duration="100" />
<item android:drawable="@drawable/ic_loading_grey_on_black_03" android:duration="100" />
<item android:drawable="@drawable/ic_loading_grey_on_black_04" android:duration="100" />
<item android:drawable="@drawable/ic_loading_grey_on_black_05" android:duration="100" />
<item android:drawable="@drawable/ic_loading_grey_on_black_06" android:duration="100" />
<item android:drawable="@drawable/ic_loading_grey_on_black_07" android:duration="100" />
<item android:drawable="@drawable/ic_loading_grey_on_black_08" android:duration="100" />
<item android:drawable="@drawable/ic_loading_grey_on_black_09" android:duration="100" />
<item android:drawable="@drawable/ic_loading_grey_on_black_10" android:duration="100" />
<item android:drawable="@drawable/ic_loading_grey_on_black_11" android:duration="100" />
<item android:drawable="@drawable/ic_loading_grey_on_black_12" android:duration="100" />

je suppose qu'une solution plus facile est d'utiliser une image par résolution, mais plutôt de la tourner pour chaque image. Dans les ressources de la plate-forme (android-sdk-windows/plates-formes...) Je j'ai trouvé quelque chose appelé animated-rotate dans le fichier drawable/search_spinner.xml, mais si je copie le code obtenir une erreur de compilateur se plaindre de android: framesCount et android: frameDuration (Google APIs 2.2 dans Eclipse):

<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/spinner_black_20"
android:pivotX="50%"
android:pivotY="50%"
android:framesCount="12"
android:frameDuration="100" />

j'ai aussi essayé d'utiliser une animation de rotation répétée (en utilisant dans le dossier de ressources anim), mais je préfère en fait l'apparence de la version de liste d'animation.

Quelle est la méthode recommandée pour résoudre ce problème?

28
demandé sur Gunnar Lium 2010-09-21 16:46:32

6 réponses

Rotate drawable suggéré par Praveen ne vous donnera pas le contrôle du nombre de trames. Supposons que vous voulez implémenter un chargeur personnalisé qui se compose de 8 sections:

gif_icon

en utilisant animation-list approche, vous avez besoin pour créer de 8 images en rotation par 45*frameNumber degrés manuellement. Alternativement, vous pouvez utiliser la 1ère image et mettre l'animation de rotation à elle:

progress_icon

le Fichier res/anim/progress_anim.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:repeatCount="infinite" />

le Fichier MainActivity.java

Animation a = AnimationUtils.loadAnimation(getContext(), R.anim.progress_anim);
a.setDuration(1000);
imageView.startAnimation(a);

cela vous donnera une animation en douceur au lieu de 8 pas. Pour corriger cela, nous devons implémenter interpolator personnalisé:

a.setInterpolator(new Interpolator() {
    private final int frameCount = 8;

    @Override
    public float getInterpolation(float input) {
        return (float)Math.floor(input*frameCount)/frameCount;
    }
});

vous pouvez aussi créer un widget personnalisé:

le Fichier res/values/attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ProgressView">
        <attr name="frameCount" format="integer"/>
        <attr name="duration" format="integer" />
    </declare-styleable>
</resources>

le Fichier ProgressView.java:

public class ProgressView extends ImageView {

    public ProgressView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setAnimation(attrs);
    }

    public ProgressView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setAnimation(attrs);
    }

    public ProgressView(Context context) {
        super(context);
    }

    private void setAnimation(AttributeSet attrs) {
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ProgressView);
        int frameCount = a.getInt(R.styleable.ProgressView_frameCount, 12);  
        int duration = a.getInt(R.styleable.ProgressView_duration, 1000);
        a.recycle();

        setAnimation(frameCount, duration);
    }

    public void setAnimation(final int frameCount, final int duration) {
        Animation a = AnimationUtils.loadAnimation(getContext(), R.anim.progress_anim);
        a.setDuration(duration);
        a.setInterpolator(new Interpolator() {

            @Override
            public float getInterpolation(float input) {
                return (float)Math.floor(input*frameCount)/frameCount;
            }
        });
        startAnimation(a);
    }
}

le Fichier activity_main.xml:

<com.example.widget.ProgressView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_progress" 
    app:frameCount="8"
    app:duration="1000"/>

le Fichier res/anim/progress_anim.xml: listés ci-dessus

56
répondu vokilam 2013-02-21 07:28:41

vous devez créer un fichier XML dessinable comme ci-dessous:

Code:

<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:pivotX="50%" android:pivotY="50%" android:fromDegrees="0"
android:toDegrees="360" android:drawable="@drawable/imagefile_to_rotate" />
13
répondu Praveen 2014-01-27 09:59:37

j'ai trouvé que la réponse de vokilam était la meilleure pour créer une belle animation pas-à-pas. Je suis allé pour sa suggestion finale et ai fait un widget personnalisé, le seul problème que j'ai rencontré était que la visibilité de réglage ne fonctionnerait pas parce qu'il était animé et donc serait toujours visible...

j'ai modifié son code (ProgressView.java que j'ai renommé StaggeredProgress.java) comme ceci:

public class StaggeredProgress extends ImageView {

private Animation staggered;

public StaggeredProgress(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    setAnimation(attrs);
}

public StaggeredProgress(Context context, AttributeSet attrs) {
    super(context, attrs);
    setAnimation(attrs);
}

public StaggeredProgress(Context context) {
    super(context);
}

private void setAnimation(AttributeSet attrs) {
    TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.StaggeredProgress);
    int frameCount = a.getInt(R.styleable.StaggeredProgress_frameCount, 12);  
    int duration = a.getInt(R.styleable.StaggeredProgress_duration, 1000);
    a.recycle();

    setAnimation(frameCount, duration);
}

public void setAnimation(final int frameCount, final int duration) {
    Animation a = AnimationUtils.loadAnimation(getContext(), R.anim.progress_anim);
    a.setDuration(duration);
    a.setInterpolator(new Interpolator() {

        @Override
        public float getInterpolation(float input) {
            return (float)Math.floor(input*frameCount)/frameCount;
        }
    });
    staggered = a;
    //startAnimation(a);
}

@Override
public void setVisibility(int visibility) {
    super.setVisibility(visibility);
    if( visibility == View.VISIBLE )
        startAnimation(staggered);
    else
        clearAnimation();

}


}

de cette façon, le réglage de la visibilité de la vue commence et arrête l'animation comme suit: requis...Merci encore à vokilam!

6
répondu user1504495 2013-05-07 10:09:08

voir les exemples ici http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/index.html

spécifiquement: Barre De Progression

  1. Incrémentielle Démontre des indicateurs de progrès rotatifs petits et grands qui peuvent être incrémentés ou décrémentés en unités.
  2. lisses Montre des indicateurs de progrès à rotation continue, petits et grands, utilisés pour indiquer un message générique "occupé".
  3. boîtes de dialogue Démontre un ProgressDialog, un dialogue popup qui héberge une barre de progression. Cet exemple montre à la fois des indicateurs de progrès déterminés et des indicateurs de progrès indéterminés.
  4. Dans La Barre De Titre Affiche un écran D'activité avec un indicateur de progrès chargé en réglant la fonction indicateur de progrès de la Politique de fenêtre.
2
répondu mishkin 2010-11-21 15:38:09

la solution de SACPK fonctionne définitivement. Une autre solution peut être d'utiliser <animated-rotate> comme dans la question et supprimer android:framesCount="12" android:frameDuration="100" attributs pour ceux que le compilateur critique. Cela fonctionne toujours, même pour mon image à 8 images.

Cependant, je havn'pas compris comment contrôler la vitesse de l'animation :(.

0
répondu ernazm 2011-10-28 10:01:48

Merci @vokilam. Cette solution similaire (une vue personnalisée qui tourne automatiquement) utilise <animation-list> dynamiquement dans sa mise en œuvre:

public class FramesAnimatorView extends AppCompatImageView {
    private int framesCount;
    private int duration;
    private Bitmap frameBitmap;

    public FramesAnimatorView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs);
    }

    public FramesAnimatorView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public FramesAnimatorView(Context context) { super(context); }

    private void init(Context context, AttributeSet attrs) {
        final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FramesAnimatorView);
        framesCount = typedArray.getInt(R.styleable.FramesAnimatorView_framesCount, 12);
        duration = typedArray.getInt(R.styleable.FramesAnimatorView_duration, 1200);
        typedArray.recycle();

        // Method 1: Use <rotate> as Animation (RotateAnimation) and startAnimation() (Rotate view itself).
        //method1(framesCount, duration);

        // Method 2: Use <rotate> as Drawable (RotateDrawable) and ObjectAnimator. Usable for API 21+ (because of using RotateDrawable.setDrawable).
        //method2();

        // Method 3 (Recommended): Use <animation-list> (AnimationDrawable) dynamically.
        final int frameDuration = this.duration / framesCount;
        final AnimationDrawable animationDrawable = (AnimationDrawable) getDrawable();

        for (int i = 0; i < framesCount; i++)
            animationDrawable.addFrame(
                    new RotatedDrawable(frameBitmap, i * 360f / framesCount, getResources()),
                    frameDuration);

        animationDrawable.start();
    }

    @Override public void setImageResource(int resId) { //info();
        frameBitmap = BitmapFactory.decodeResource(getResources(), resId);
        super.setImageDrawable(new AnimationDrawable());
    }

    @Override public void setImageDrawable(@Nullable Drawable drawable) { //info();
        frameBitmap = drawableToBitmap(drawable);
        super.setImageDrawable(new AnimationDrawable());
    }

    @Override public void setImageBitmap(Bitmap bitmap) { //info();
        frameBitmap = bitmap;
        super.setImageDrawable(new AnimationDrawable());
    }

    /**
     * See <a href="https://stackoverflow.com/a/21376008/5318303">@android-developer's answer on stackoverflow.com</a>.
     */
    private static class RotatedDrawable extends BitmapDrawable {
        private final float degrees;
        private int pivotX;
        private int pivotY;

        RotatedDrawable(Bitmap bitmap, float degrees, Resources res) {
            super(res, bitmap);
            pivotX = bitmap.getWidth() / 2;
            pivotY = bitmap.getHeight() / 2;
            this.degrees = degrees;
        }

        @Override public void draw(final Canvas canvas) {
            canvas.save();
            canvas.rotate(degrees, pivotX, pivotY);
            super.draw(canvas);
            canvas.restore();
        }
    }

    /**
     * See <a href="https://stackoverflow.com/a/10600736/5318303">@André's answer on stackoverflow.com</a>.
     */
    @NonNull private static Bitmap drawableToBitmap(Drawable drawable) {
        final Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        final Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        return bitmap;
    }
}

Voir Android-FramesAnimatorView on GitHub complet (et probablement plus mis à jour) le code source.

0
répondu Mir-Ismaili 2018-08-10 23:06:05