名称 | 类型 | 子类 | 标签 | 效果 |
---|---|---|---|---|
平移动画 | view动画 | TranslateAnimation | < translate > | 移动view |
缩放动画 | view动画 | ScaleAnimation | < scale > | 放大或缩小view |
旋转动画 | view动画 | RotateAnimation | < RotateAnimation> | 旋转view |
透明度动画 | view动画 | AlphaAnimation | < AlphaAnimation> | 改变view的透明度 |
帧动画 | view动画 | AnimationDrawable | < animation-list > | 顺序播放一组预先定义好的的图片 |
layoutAnimation动画 | view动画 | AnimationDrawable | < layoutAnimation> | 作用于viewgroup,子元素出厂时都具有此效果 |
属性动画 | 属性动画 |
<?xml version="1.0" encoding="utf-8"?>
<!-- set对应得是动画集合,对应类是AnimationSet,-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1"
android:fillAfter="true"
android:shareInterpolator="true">
<!-- 表示集合中的动画是否和集合共享一个插值器,duration是指持续时间,fillAfter动画结束后view是否停留在结束位置-->
<!-- 表示透明度动画-->
<alpha
android:fromAlpha="1"
android:toAlpha="0"></alpha>
<!-- 表示缩放动画,默认缩放轴点为view中心,左右方向同时缩放,若设右边界,view只会向左边进行缩放-->
<scale
android:fromXScale="1"
android:toXScale="0"
android:fromYScale="1"
android:toYScale="0"
android:pivotY="1"
android:pivotX="1"
>
</scale>
<!-- 表示在水平和垂直方法平移动画-->
<translate
android:fromXDelta="1"
android:fromYDelta="1"
android:toXDelta="0"
android:toYDelta="0">
</translate>
<!-- 表示旋转动画,默认view的中心为旋转轴-->
<rotate
android:fromDegrees="10"
android:pivotX="1"
android:pivotY="1"
android:toDegrees="30">
</rotate>
</set>
加载动画
Animation animation= AnimationUtils.loadAnimation(this,R.anim.demo);
m.startAnimation(animation);
帧动画xml,帧动画的xml要写的drawable下面,animation-list才能识别
<?xml version="1.0" encoding="utf-8"?>
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true"
>
<item android:drawable="@drawable/icon1" android:duration="150"></item>
<item android:drawable="@drawable/icon2" android:duration="150"></item>
<item android:drawable="@drawable/icon3" android:duration="150"></item>
<item android:drawable="@drawable/icon4" android:duration="150"></item>
<item android:drawable="@drawable/icon5" android:duration="150"></item>
<item android:drawable="@drawable/icon6" android:duration="150"></item>
</animation-list>
m.setBackgroundResource(R.drawable.demo1);
AnimationDrawable drawable=(AnimationDrawable)m.getBackground();
drawable.start();
LayoutAnimation作用于Viewgroup,当其子元素出场时也具有这种效果,一般用于listview这种带列表的控件。
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation
xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="0.5"
android:animationOrder="normal"
android:animation="@anim/demo1">
<!--假如demo1动画周期为1000ms,那么0.5表示每个item出场都需延时500ms,
第一个是500ms,第二个就是1000ms,animationOrder为子元素的动画顺序,比如随机出场和逆向出场,
对于listview,只需给其加上android:layoutAnimation这个属性就好-->
</layoutAnimation>
Activity的切换效果主要方法:
//此方法只能在startactivity和finish()之后被调用才有效。
overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);
Fragment切换效果主要方法:
//这里动画必须是View动画
FragmentTransaction transaction= getChildFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.enter_anim,R.anim.exit_anim);
属性动画ObjectAnimator , ValueAnimator, AnimatorSet
属性动画是API11加入的属性,可对任何对象做动画,动画默认的时间间隔是300ms,默认帧率10ms/帧,达到的效果是在一个时间间隔内
完成对象从一个属性值到另一个属性值的改变。兼容库nineoldandroids,网址:http://nineoldandroid.com,属性动画要求对象
的该属性有get/set方法
ObjectAnimator例子,它是ValueAnimator的子类
ObjectAnimator.ofFloat(myObject,"translationY",-myObject.getHeight).start();
ValueAnimator例子
ValueAnimator colorAnimator=ObjectAnimator.ofInt
(this,"backgroundColor",/*RED*/0XFFFF8080,/*RED*/0XFF8080FF);
colorAnimator.setDuration(3000);
colorAnimator.setEvaluator(new ArgbEvaluator());
colorAnimator.setRepeatCount(ValueAnimator.INFINITE);
colorAnimator.setRepeatMode(ValueAnimator.REVERSE);
colorAnimator.start();
####AnimatorSet例子
AnimatorSet set=new AnimatorSet();
set.playTogether(
ObjectAnimator.ofInt(myView,"rotationX",0,360),
ObjectAnimator.ofInt(myView,"rotationY",0,180)
);
set.setDuration(5*1000).start();
属性动画通过XML定义,需要定义在res/animator目录下
<set
android:ordering="sequentially"
xmlns:android="http://schemas.android.com/apk/res/android"><!-- 播放方式,按顺序还是一起播放-->
<objectAnimator>
</objectAnimator>
<animator>
</animator><!--ValueAnimator-->
</set><!--AnimatorSet-->
插值器和估值器
自定义插值器需要实现Interpolator或者TimeInterpolator,自定义估值算法需要实现TypeEvaluator.另外如果要对其他类型(非
int、float、Color)做动画,那么必须要自定义类型估值算法,可参考http://www.weidu8.net/wx/140849。
属性动画的监听器
ValueAnimator.AnimatorUpdateListener
public void onAnimationUpdate(ValueAnimator animation);
监听动画的整个过程,每播放一帧就会被调用一次
Animator.AnimatorListener
public void onAnimationStart(Animator animation) ;
public void onAnimationEnd(Animator animation);
public void onAnimationCancel(Animator animation);
public void onAnimationRepeat(Animator animation);
属性动画的要求
1、object必须提供setXX/getXX属性的方法,当没有初始值的时候需要调get方法获取,否则程序cash。
2、object提供的setXX所做的改变必须能够通过某种方法反应出来,否则动画无效果。
想要满足上面两条件的话,有3种方法,如下:
1,给你的对象加上get和set方法,如果你有权限的话
2,用一个类来包装原始对象,间接为其提供get和set方法
3,采用ValueAnimator,监听动画的过程,自己实现属性的改变
如下:
package site.zhangyun.appliction;
import android.animation.IntEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import com.efrobot.library.RobotManager;
import com.efrobot.library.RobotState;
import com.efrobot.library.task.ControlManager;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button mBtLight, mBtLightPutout;
RobotManager mRobotManager;
ObjectAnimator mObjectAnimator;
ValueAnimator valueAnimator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InitViews();
}
void InitViews() {
mBtLight = (Button) findViewById(R.id.lightchange);
mBtLight.setOnClickListener(this);
mBtLightPutout = (Button) findViewById(R.id.light_putout);
mBtLightPutout.setOnClickListener(this);
mRobotManager = RobotManager.getInstance(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.lightchange:
//坑一:android系统里面吧动画设置给关闭了导致播放不了动画,找了一下午的bug,555....
//实现呼吸灯的效果
mObjectAnimator = ObjectAnimator.ofInt(new myTest(mRobotManager, this), "lightBeltBrightness", 0, 255);
mObjectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentValue = (Integer) animation.getAnimatedValue();
Log.d("当前灯带亮度", currentValue + "");
}
});
mObjectAnimator.setRepeatCount(ValueAnimator.INFINITE);//死循环
mObjectAnimator.setRepeatMode(ValueAnimator.REVERSE);//先从熄灭到亮,再从亮到熄灭
mObjectAnimator.setInterpolator(new LinearInterpolator());//线性变换一次递增
mObjectAnimator.setDuration(1000 * 10);//动画执行时间为10秒
mObjectAnimator.start();
//ValueAnimator实现允许变化从0到255
performAnimator(ControlManager.getInstance(mRobotManager), 0, 255);
break;
case R.id.light_putout:
ControlManager.getInstance(mRobotManager).setLightBeltBrightness(0);
if (mObjectAnimator != null) {
mObjectAnimator.cancel();
}
break;
}
}
void performAnimator(final ControlManager controlManager, final int start, final int end) {
valueAnimator = ValueAnimator.ofInt(0, 255);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
private IntEvaluator mEvaluator = new IntEvaluator();//整形估值器,匀速
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//获取当前动画的进度值
int currentValue = (Integer) animation.getAnimatedValue();
//获取当前的进度占整个动画过程的比例
float fraction = animation.getAnimatedFraction();
//设置灯带的亮度
controlManager.setLightBeltBrightness(mEvaluator.evaluate(fraction, start, end));
//呼吸灯是抛物线,0-255-0,自己算吧y=(-51/5)*t2+102t
}
});
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
valueAnimator.setDuration(1000 * 10).start();
}
//ControlManager里面只有set木有get于是乎就得自己实现啦
class myTest extends ControlManager {
ControlManager mControlManager;
RobotState mRobotState;
myTest(RobotManager robotManager, Context context) {
super(robotManager);
mControlManager = ControlManager.getInstance(mRobotManager);
mRobotState = RobotState.getInstance(context);
}
public int getLightBeltBrightness() {
return mRobotState.getLightBeltBrightness();
}
public void setLightBeltBrightness(int lightBeltBrightness) {
mControlManager.setLightBeltBrightness(lightBeltBrightness);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//这里要是不调用的话,就会内存泄漏
//当动画为无限循环动画的时候,动画持有view,view持有activity,那么activity无法释放,内存泄漏
if (mObjectAnimator != null) {
mObjectAnimator.cancel();
}
if (valueAnimator != null) {
valueAnimator.cancel();
}
}
}
使用动画的注意事项
1、当图片的数量过多较大时极易容易出现OOM,开发中应尽量避免。
2、无限循环属性动画容易造成内存泄漏,需要在activity退出时及时停止,view动画不存在此问题。
3、view动画是对view的影像做动画,并不是真的改变状态,有时出现动画完成后view无法隐藏问题,可以先调用view.clearAnimation()。
4、进行动画时尽可能使用dp,px会导致在不同设备有不同效果
5、从3.0开始,属性动画的单击事件触发位置为移动后的位置,但view动画任然在原位置。
6,开启硬件加速可以提高动画流畅性
7,动画在3.0以下有兼容问题