Rotierendes Bild. Animationsliste oder animierte Drehung? (Android)

Lesezeit: 8 Minuten

Ich möchte ein rotierendes Fortschrittsbild erstellen und frage mich, wie ich am besten vorgehen soll. Ich kann es mit einer Animationsliste mit beispielsweise 12 Bildern zum Laufen bringen, die sich alle 100 ms ändern. Das funktioniert gut, aber es ist ziemlich mühsam, 12 Bilder oder für jede Größe und Auflösung zu erstellen:

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

Ich nehme an, eine einfachere Lösung besteht darin, ein Bild pro Auflösung zu verwenden, sondern es für jeden Frame zu drehen. In den Plattformressourcen (android-sdk-windows/platforms…) habe ich in der Datei drawable/search_spinner.xml etwas namens animierte-rotieren gefunden, aber wenn ich den Code kopiere, erhalte ich einen Compilerfehler, der sich über android:framesCount und android beschwert: frameDuration (Google APIs 2.2 in 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" />

Ich habe auch versucht, eine sich wiederholende Rotationsanimation zu verwenden (im Anim-Ressourcenordner), aber ich bevorzuge das Aussehen der Animationslistenversion.

Was ist der empfohlene Weg, dieses Problem zu lösen?

Rotate drawable von Praveen vorgeschlagen, gibt Ihnen keine Kontrolle über die Bildanzahl. Nehmen wir an, Sie möchten einen benutzerdefinierten Loader implementieren, der aus 8 Abschnitten besteht:

gif_icon

Verwenden von animation-list Ansatz müssen Sie 8 Frames gedreht erstellen um 45*frameNumber Grad manuell. Alternativ können Sie den 1. Frame verwenden und die Rotationsanimation darauf einstellen:

progress_icon

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

Datei MainActivity.java

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

Dadurch erhalten Sie eine reibungslose Animation anstelle einer 8-stufigen. Um dies zu beheben, müssen wir einen benutzerdefinierten Interpolator implementieren:

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

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

Sie können auch ein benutzerdefiniertes Widget erstellen:

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

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

Datei activity_main.xml:

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

Datei res/anim/progress_anim.xml: oben aufgelistet

  • Ich kann die Fortschrittsansicht nicht ausblenden, indem ich verwende android:visibility="invisible" irgendein grund?

    – Prateek

    9. Juni ’14 um 11:04

  • das ist eine tolle Erklärung, danke! Für diejenigen, die Probleme mit dem Interpolator haben, habe ich einfach Folgendes verwendet: a.setInterpolator(new LinearInterpolator()); und es funktioniert gut!

    – Couitchy

    29. Juli ’14 um 12:48


  • Wie erzwinge ich das Stoppen der Animation?

    – hasan

    5. Apr. ’15 um 7:15

  • Nützliche Fortschritte myandroidwidgets.googlecode.com/svn/trunk/Custom_Progress_Bar/…

    – DeepakPanwar

    22. Juli ’15 um 0:01


  • blog.mediarain.com/2011/04/…

    – DeepakPanwar

    22. Juli ’15 um 0:04

1641780726 263 Rotierendes Bild Animationsliste oder animierte Drehung Android
Praveen

Sie müssen eine zeichenbare XML-Datei wie folgt erstellen:

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

  • Wie kommt es, dass es sich nicht dreht?

    – Mark Molina

    19. Juni ’14 um 16:43

  • Auf einigen Geräten funktioniert es nicht. Bitte verwenden Sie stattdessen Rotage

    – vuhung3990

    22. Juli ’15 um 9:07

Ich fand die Antwort von vokilam die beste, um eine schöne abgestufte / gestaffelte Animation zu erstellen. Ich habe mich für seinen letzten Vorschlag entschieden und ein benutzerdefiniertes Widget erstellt. Das einzige Problem, auf das ich gestoßen bin, war, dass das Einstellen der Sichtbarkeit nicht funktionierte, da es animiert war und daher immer sichtbar war …

Ich habe seinen Code (ProgressView.java, das ich in StaggeredProgress.java umbenannt habe) wie folgt angepasst:

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

}


}

Auf diese Weise wird die Sichtbarkeit der Ansicht eingestellt, um die Animation nach Bedarf zu starten und zu stoppen… Nochmals vielen Dank an vokilam!

siehe Beispiele hier
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/index.html

speziell: Fortschrittsbalken

  1. Inkrementell Zeigt große und kleine rotierende Fortschrittsanzeigen an, die in Einheiten erhöht oder verringert werden können.
  2. Glatt Zeigt große und kleine, sich kontinuierlich drehende Fortschrittsanzeigen an, die verwendet werden, um eine allgemeine „Besetzt“-Meldung anzuzeigen.
  3. Dialogs Demonstriert einen ProgressDialog, einen Popup-Dialog, der einen Fortschrittsbalken hostet. Dieses Beispiel zeigt sowohl bestimmte als auch unbestimmte Fortschrittsindikatoren.
  4. In der Titelleiste Demonstriert einen Aktivitätsbildschirm mit einer geladenen Fortschrittsanzeige, indem die Fortschrittsanzeigefunktion von WindowPolicy eingestellt wird.

Die Lösung von SACPK funktioniert definitiv. Eine andere Lösung kann sein, zu verwenden <animated-rotate> genau wie in frage und entfernen android:framesCount="12"
android:frameDuration="100"
Attribute für diejenigen, die der Compiler beschwert. Es funktioniert immer noch, sogar für mein 8-Frame-Bild.

Ich habe jedoch nicht herausgefunden, wie man die Geschwindigkeit der Animation steuert :(.

Rotierendes Bild Animationsliste oder animierte Drehung Android
Mir-Ismaili

Danke @vokilam. Diese ähnliche Lösung (eine benutzerdefinierte Ansicht, die sich automatisch dreht) verwendet <animation-list> dynamisch in der Umsetzung:

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

Sehen Android-FramesAnimatorAuf GitHub ansehen für vollständigen (und wahrscheinlich aktualisierteren) Quellcode.

.

262430cookie-checkRotierendes Bild. Animationsliste oder animierte Drehung? (Android)

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy