【问题标题】:Rotating image. Animation list or animated rotate? (Android)旋转图像。动画列表或动画旋转? (安卓)
【发布时间】:2011-04-15 04:39:11
【问题描述】:

我想创建一个旋转的进度图像,并想知道如何进行的最佳方式。我可以使其与动画列表一起使用,例如每 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" />

我想一个更简单的解决方案是每个分辨率使用一个图像,而是为每一帧旋转它。在平台资源 (android-sdk-windows/platforms...) 中,我在文件 drawable/search_spinner.xml 中发现了一些名为动画旋转的东西,但是如果我复制代码,则会出现编译器错误,抱怨 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" />

我也尝试过使用重复旋转动画(在动画资源文件夹中使用),但我实际上更喜欢动画列表版本的外观。

解决此问题的推荐方法是什么?

【问题讨论】:

    标签: android animation rotation


    【解决方案1】:

    Praveen 建议的Rotate drawable 不会让您控制帧数。假设您要实现一个由 8 个部分组成的自定义加载器:

    使用animation-list 方法,您需要手动创建8 个旋转45*frameNumber 度的帧。或者,您可以使用第一帧并为其设置旋转动画:

    文件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:以上列出

    【讨论】:

    【解决方案2】:

    您必须创建一个可绘制的 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" />
    

    【讨论】:

    • 它怎么不旋转?
    • 它不适用于某些设备。请改用轮换
    【解决方案3】:

    我发现 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!

    【讨论】:

      【解决方案4】:

      在此处查看示例 http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/index.html

      具体来说: 进度条

      1. 增量 演示可以以单位递增或递减的大小旋转进度指示器。
      2. 光滑 演示用于指示通用“忙碌”消息的大小不断旋转的进度指示器。
      3. 对话框 演示 ProgressDialog,这是一个包含进度条的弹出对话框。此示例演示了确定和不确定的进度指示器。
      4. 在标题栏中 通过设置 WindowPolicy 的进度指示器功能,演示带有进度指示器的 Activity 屏幕。

      【讨论】:

        【解决方案5】:

        SACPK 的解决方案绝对有效。另一种解决方案是使用 &lt;animated-rotate&gt; 就像有问题的一样,并删除编译器抱怨的 android:framesCount="12" android:frameDuration="100" 属性。即使对于我的 8 帧图像,它仍然有效。

        但是,我还没有弄清楚如何控制动画的速度:(。

        【讨论】:

          【解决方案6】:

          感谢@vokilam。这个类似的解决方案(一个自动旋转的自定义视图)在其实现中动态使用&lt;animation-list&gt;

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

          请参阅Android-FramesAnimatorView on GitHub 以获取完整(可能还有更多更新)源代码。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-07-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多