web-dev-qa-db-ja.com

画像を回転させます。アニメーションリストまたはアニメーション回転? (アンドロイド)

回転進行イメージを作成したいのですが、どのように進めるのが最善かと思います。たとえば、100ミリ秒ごとに変化する12枚の画像を含むアニメーションリストで動作させることができます。これは正常に機能しますが、12個の画像を作成したり、サイズや解像度ごとに作成するのは非常に面倒です。

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

より簡単な解決策は、解像度ごとに1つの画像を使用することですが、フレームごとに画像を回転させることです。プラットフォームリソース(Android-sdk-windows/platforms ...)で、ファイルdrawable/search_spinner.xmlにanimated-rotateと呼ばれるものが見つかりましたが、コードをコピーすると、Android:framesCountとAndroidについて不平を言うコンパイラエラーが発生します。 frameDuration(EclipseのGoogle API 2.2):

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

また、繰り返し回転アニメーション(animリソースフォルダーで使用)を使用しようとしましたが、実際にはアニメーションリストバージョンの外観を好みます。

この問題を解決する推奨される方法は何ですか?

29
Gunnar Lium

Praveenが提案したRotate drawableでは、フレームカウントを制御できません。 8つのセクションで構成されるカスタムローダーを実装するとします。

gif_icon

animation-listアプローチを使用して、45*frameNumber度回転した8つのフレームを手動で作成する必要があります。または、最初のフレームを使用して、それに回転アニメーションを設定できます。

progress_icon

ファイル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" />

ファイルMainActivity.Java

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

これにより、8ステップではなくスムーズなアニメーションが得られます。これを修正するには、カスタム補間を実装する必要があります。

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

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

また、カスタムウィジェットを作成することもできます。

ファイル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>

ファイル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);
    }
}

ファイル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"/>

ファイルres/anim/progress_anim.xml:上記のリスト

62
vokilam

以下のようなドローアブルxmlファイルを作成する必要があります。

コード:

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

ニースのステップ/スタッガードアニメーションを作成するには、vokilamの答えが最適であることがわかりました。私は彼の最後の提案に行き、カスタムウィジェットを作成しましたが、遭遇した唯一の問題は、可視性の設定が機能しなかったということでした。

私は彼のコード(ProgressView.JavaをStaggeredProgress.Javaと改名しました)を次のように調整しました。

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

}


}

このようにして、ビューの可視性を設定すると、必要に応じてアニメーションが開始および停止します...再びvokilamに感謝します!

7
user1504495

こちらの例をご覧ください http://developer.Android.com/resources/samples/ApiDemos/src/com/example/Android/apis/view/index.html

具体的には、進行状況バー

  1. 増分単位で増分または減分できる、大小の回転進行インジケーターを示します。
  2. Smooth汎用の「ビジー」メッセージを示すために使用される、大小の連続的に回転する進行状況インジケーターを示します。
  3. ダイアログプログレスバーをホストするポップアップダイアログであるProgressDialogを示します。この例は、確定的な進行状況インジケーターと不確定な進行状況インジケーターの両方を示しています。
  4. タイトルバーでWindowPolicyの進行状況インジケーター機能を設定して、進行状況インジケーターが読み込まれたアクティビティ画面を示します。
2
mishkin

@vokilamに感謝します。この同様のソリューション(自動的に回転するカスタムビュー)では、<animation-list>実装で動的に:

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

完全な(およびおそらくより更新された)ソースコードについては、 GitHubのAndroid-FramesAnimatorView を参照してください。

0
Mir-Ismaili

SACPKのソリューションは間違いなく機能します。別の解決策は、<animated-rotate>質問と同じように削除してAndroid:framesCount="12" Android:frameDuration="100"コンパイラーが不平を言うそれらの属性。 8フレームの画像でも機能します。

ただし、アニメーションの速度を制御する方法がわかりませんでした:(。

0
ernazm