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:

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:

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

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" />
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
- Inkrementell Zeigt große und kleine rotierende Fortschrittsanzeigen an, die in Einheiten erhöht oder verringert werden können.
- Glatt Zeigt große und kleine, sich kontinuierlich drehende Fortschrittsanzeigen an, die verwendet werden, um eine allgemeine „Besetzt“-Meldung anzuzeigen.
- Dialogs Demonstriert einen ProgressDialog, einen Popup-Dialog, der einen Fortschrittsbalken hostet. Dieses Beispiel zeigt sowohl bestimmte als auch unbestimmte Fortschrittsindikatoren.
- 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 :(.

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.
.
2624300cookie-checkRotierendes Bild. Animationsliste oder animierte Drehung? (Android)yes