废话不说,先上图
这样一个图如果需要让中间的正方形逆时针转,外层正方形顺时针转,你会怎么做?
1.简单,弄两个ImageView然后让他们转起来就好了。
貌似这样做确实比较简单,但如果正方形数量比较多的时候就尴尬了,或者我要让这个动画当某段文字的背景,这种做法就比较麻烦了
2.用gif图实现
gif图较大,且拉伸容易失真
3.帧动画
将动画拆分成n个图片,顺序播放。对于一些简单动画没必要这样做,如旋转放大这些,我们只要一张图片然后自己加动画就可以实现了。
接下来说说我的做法:
layer-list这个标签相信大家都不陌生,他可以实现将多个drawable嵌套在一起
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_action_big"/>
<item android:drawable="@drawable/ic_action_small"/>
</layer-list>
像这样,上面那个图就做出来了,那如何在这基础上增加动画呢?
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<animated-rotate
android:drawable="@drawable/ic_action_big"
android:pivotX="50%"
android:pivotY="50%"/>
</item>
<item>
<animated-rotate
android:drawable="@drawable/ic_action_small"
android:pivotX="50%"
android:pivotY="50%"/>
</item>
</layer-list>
google也提供了一些简单的动画让我们选,如旋转当然代码里还要手动让动画跑起来
View view = findViewById(R.id.vp);
LayerDrawable drawable = (LayerDrawable) view.getBackground();
Animatable a = (Animatable) drawable.getDrawable(0);
Animatable b = (Animatable) drawable.getDrawable(1);
a.start();
b.start();
轻松转起来,效果如下:
说好的一个顺时针一个逆时针呢?
由于animated-rotate封装的比较严,没有更多的属性可以设置。先翻翻源码看看吧!
实现类是AnimatedRotateDrawable
private final Runnable mNextFrame = new Runnable() {
@Override
public void run() {
// TODO: This should be computed in draw(Canvas), based on the amount
// of time since the last frame drawn
mCurrentDegrees += mIncrement;
if (mCurrentDegrees > (360.0f - mIncrement)) {
mCurrentDegrees = 0.0f;
}
invalidateSelf();
nextFrame();
}
};
这段代码我们可以知道是mIncrement变量控制动画每一次刷新旋转的角度和方向,由于这个类是@hide注释的,我们无法直接获得,所以通过反射来设置
View view = findViewById(R.id.vp);
LayerDrawable drawable = (LayerDrawable) view.getBackground();
Animatable a = (Animatable) drawable.getDrawable(0);
Animatable b = (Animatable) drawable.getDrawable(1);
try {
a.getClass().getDeclaredMethod("setFramesCount",int.class).invoke(b,-12);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
a.start();
b.start();
设置为负数就是逆时针旋转了,但需要注意的是源码里每转一圈就会将mCurrentDegrees置零,所以可以无限转圈,设置为负数后这个重置就无效了,经计算,按1.8s旋转一圈的速度大约经过11小时后就会爆掉float上限,不过几乎不会一直让他播放11个小时,哈哈!
最后附上效果图: