Android动画可以分为两类,最初的传统动画和Android3.0 之后出现的属性动画;其中传统动画还分为,补间动画(Tweened Animation)和帧动画(Frame Animation)
补间动画:(现在res创建一个文件夹,然后在文件夹下面创建一个.xml文件)
补间动画分为,淡入淡出,伸缩,位移,旋转 4种
alpha(淡入淡出)
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromAlpha="1"
android:toAlpha="0"
android:interpolator="@android:anim/linear_interpolator"
android:repeatCount="2"
>
</alpha>
translate(位移)
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromXDelta="1"
android:fromYDelta="1"
android:interpolator="@android:anim/linear_interpolator"
android:repeatCount="2"
android:toXDelta="100"
android:toYDelta="100" >
</translate>
scale(缩放大小)
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1500"
android:fromXScale="1"
android:toXScale="3"
android:fromYScale="1"
android:toYScale="3"
android:interpolator="@android:anim/linear_interpolator"
android:repeatCount="2"
>
</scale>
rotate(旋转)
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromDegrees="1"
android:toDegrees="720"
android:pivotX="50%"
android:pivotY="50%"
android:interpolator="@android:anim/linear_interpolator"
android:repeatCount="2"
>
</rotate>
其实可以将这些动画添加到set标签里面:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="true"
android:interpolator="@android:anim/linear_interpolator"
>
<alpha
android:duration="3000"
android:fromAlpha="1.0"
android:toAlpha="0"
/>
<translate
android:duration="3000"
android:fromXDelta="0"
android:toXDelta="100"
/>
<rotate
android:duration="3000"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
/>
</set>
具体代码实现如下:
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AlphaAnimation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity implements OnClickListener {
private Button mBtn1,mBtn2,mBtn3,mBtn4,mBtn5;
private ImageView mImg;
private AlphaAnimation alpha;
private ScaleAnimation scale;
private TranslateAnimation translat;
private RotateAnimation rotate;
private AnimationUtils utils;//动画工具类
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
utils=new AnimationUtils();
initView();
}
private void initView() {
mBtn1=(Button) findViewById(R.id.mBtn1);
mBtn2=(Button) findViewById(R.id.mBtn2);
mBtn3=(Button) findViewById(R.id.mBtn3);
mBtn4=(Button) findViewById(R.id.mBtn4);
mBtn5=(Button) findViewById(R.id.mBtn5);
mImg=(ImageView) findViewById(R.id.mImg);
mBtn1.setOnClickListener(this);
mBtn2.setOnClickListener(this);
mBtn3.setOnClickListener(this);
mBtn4.setOnClickListener(this);
mBtn5.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int ID=v.getId();
switch (ID) {
case R.id.mBtn1:
alpha=(AlphaAnimation) utils.loadAnimation(this, R.anim.alpha_anim);
mImg.startAnimation(alpha);
break;
case R.id.mBtn2:
scale=(ScaleAnimation) utils.loadAnimation(this, R.anim.scale_anim);
mImg.startAnimation(scale);
break;
case R.id.mBtn3:
translat=(TranslateAnimation) utils.loadAnimation(this, R.anim.translate_anim);
mImg.startAnimation(translat);
break;
case R.id.mBtn4:
rotate=(RotateAnimation) utils.loadAnimation(this, R.anim.rotate_anim);
mImg.startAnimation(rotate);
break;
case R.id.mBtn5:
AnimationSet set=(AnimationSet) utils.loadAnimation(this, R.anim.set_anim);
mImg.startAnimation(set);
break;
}
}
}
帧动画:
(我就用我的理解说一下帧动画,帧动画就是把一些图片放在一个集合或者是定义的.xml文件里面,然后让它们一张一张的播放起来,如果是一组连贯的图片,给我们带来的感觉就是这个图片一直在动,其实这是图片的轮换带来的效果,具体设置动画的属性,代码里面有介绍,让我们一起来看看吧)
首先先导入几张图片:(这几张图片动起来就像是一只真实的小宠物,白色皮卡丘)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
>
<Button
android:id="@+id/mBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="开始动画"
/>
<ImageView
android:id="@+id/mImg"
android:layout_width="200dp"
android:layout_height="200dp"
/>
</LinearLayout>
代码实现类:(就这简单的一个类,就实现了帧动画,而且我写的还是比较复杂点的)//功能实现:点击按钮动画开始 ,点击图片控制动画启动与停止
import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity implements OnClickListener {
private Button mBtn;
private ImageView mImg;
//将本地的图片加入到图片数组中
int []animArr={R.mipmap.ani1,R.mipmap.ani2,R.mipmap.ani3,R.mipmap.ani4};
//帧动画类
AnimationDrawable ad;
private boolean flag=true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ad=new AnimationDrawable();//实例化
initView();
//初始化帧动画数据源
initAnim();
}
//初始化动画
@SuppressLint("NewApi")
private void initAnim() {
for(int i=0;i<animArr.length;i++){
//依次将本地图片添加到帧动画中 :获取系统获取本地资源的方法:getResources().getDrawable()
ad.addFrame(getResources().getDrawable(animArr[i]), 150);
}
//是否只执行一次:false:否,循环执行 true:是,只执行依次
ad.setOneShot(false);
//将帧动画设置给图片
mImg.setImageDrawable(ad);
}
private void initView() {
mBtn=(Button) findViewById(R.id.mBtn);
mImg=(ImageView) findViewById(R.id.mImg);
mBtn.setOnClickListener(this);
mImg.setOnClickListener(this);
}
//功能实现:点击按钮动画开始 ,点击图片控制动画启动与停止
@Override
public void onClick(View v) {
if(R.id.mBtn==v.getId()){
ad.start();
}else{
if(flag){
ad.stop();
flag=false;
}else{
ad.start();
flag=true;
}
}
}
}
属性动画:
属性动画看似和补间动画差不多,但是却有本质的变化,属性动画能改变控件本身的位置,而补间动画不行。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
>
<ImageView
android:id="@+id/mImg"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@mipmap/ic_launcher"
/>
<Button
android:id="@+id/mBtn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="平移"
/>
<Button
android:id="@+id/mBtn2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="缩放"
/>
<Button
android:id="@+id/mBtn3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="旋转"
/>
<Button
android:id="@+id/mBtn4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="透明"
/>
</LinearLayout>
具体代码实现:
import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity implements OnClickListener {
private ImageView mImg;
private Button mBtn1,mBtn2,mBtn3,mBtn4;
ObjectAnimator animator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mImg=findViewById(R.id.mImg);
mBtn1=findViewById(R.id.mBtn1);
mBtn2=findViewById(R.id.mBtn2);
mBtn3=findViewById(R.id.mBtn3);
mBtn4=findViewById(R.id.mBtn4);
mBtn1.setOnClickListener(this);
mBtn2.setOnClickListener(this);
mBtn3.setOnClickListener(this);
mBtn4.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.mBtn1://平移
animator = ObjectAnimator.ofFloat(mImg, "translationX", 0.0f, 350.0f, 0f);
animator.setDuration(2500).start();
break;
case R.id.mBtn2://缩放
animator = ObjectAnimator.ofFloat(mImg, "scaleX", 1.0f, 1.5f);
animator.setDuration(2000).start();
break;
case R.id.mBtn3://旋转
animator = ObjectAnimator.ofFloat(mImg, "rotationX", 0.0f, 90.0f,0.0F);
animator.setDuration(2000).start();
break;
case R.id.mBtn4://透明
animator = ObjectAnimator.ofFloat(mImg, "alpha", 1.0f, 0.3f, 1.0F);
animator.setDuration(2000);//动画时间
break;
}
}
}
是不是感觉很简单?两行代码就能实现一个动画效果,当然只是一个简单的动画配置,如果你需要更加好的效果动画,你可以通过这些方法去配置:
- setInterpolator():设置动画插值
- setDuration():设置动画执行时间
- setRepeatCount():设置动画重复次数
- setRepeatMode():设置动画重复模式
- setStartDelay():设置动画延时操作
- setTarget():设置动画的对象
- setEvaluator():设置动画过度的评估者。
具体配置如下
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.3f, 1.0F);
animator.setDuration(2000);//动画时间
animator.setInterpolator(new BounceInterpolator());//动画插值
animator.setRepeatCount(-1);//设置动画重复次数
animator.setRepeatMode(ValueAnimator.RESTART);//动画重复模式
animator.setStartDelay(1000);//动画延时执行
animator.start();//启动动画
如果使用组合动画就是两种动画一块使用:
ObjectAnimator animator = ObjectAnimator.ofInt(container, "backgroundColor", 0xFFFF0000, 0xFFFF00FF);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageView, "translationX", 0.0f, 200.0f, 0f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(imageView, "scaleX", 1.0f, 2.0f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(imageView, "rotationX", 0.0f, 90.0f, 0.0F);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.2f, 1.0F);
//组合动画方式1
AnimatorSet set = new AnimatorSet();
((set.play(animator).with(animator1).before(animator2)).before(animator3)).after(animator4);
set.setDuration(5000);
set.start();
动画监听器
很多时候我们可能要在某一个动画执行之前 或者动画结束之后进行一些其他的操作,比如:动画结束之后进行网络数据请求等。那么我们就需要去获得该动画的一些状态,幸好,android系统给我们提供了一个动画监听器接口,来监听不同状态下的动画情况。实现也很简单,只要调用addListener(AnimatorListener listener)方法给动画添加监听器就好了,然后实现AnimatorListener接口即可。代码如下:
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
//TODO 动画开始前的操作
/**
* 比如这里可以初始化一些UI
*/
}
@Override
public void onAnimationEnd(Animator animation) {
//TODO 动画结束的操作
/**
* 比如这里可以等动画结束进行一些账号登录或者网络数据请求等。
*/
}
@Override
public void onAnimationCancel(Animator animation) {
//TODO 动画取消的操作
}
@Override
public void onAnimationRepeat(Animator animation) {
//TODO 动画重复的操作
}
});
可以根据不同需求来实现接口里面的四个方法。有时候你会觉得我不需要监听动画的四种状态,我只需要监听动画结束时候的状态,如果使用上面的方法就会感觉代码臃肿了,不过没关系,Android系统给我们提供了一个更好用的方法
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//TODO 动画结束的操作
/**
* 比如这里可以等动画结束进行一些账号登录或者网络数据请求等。
*/
}
});
可以看出,我们使用了AnimatorListenerAdapter 动画接口适配器代替AnimatorListener接口。其实AnimatorListenerAdapter的源码只是一个实现了AnimatorListener接口的抽象类而已,你需要监听哪种动画状态就重写哪种方法就可以了。是不是觉得这个方法很nice~?如果你仅仅满足于这个那就OUT了,Android系统还给我们提供了一个更加精确的方法来时刻监听当前动画的执行情况。那就是addUpdateListener(AnimatorUpdateListener listener)方法了。调用该方法只需实现AnimatorUpdateListener接口就可以读取到动画的每个更新值了。来看看代码:
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
//可以根据自己的需要来获取动画更新值。
Log.e("TAG", "the animation value is " + value);
}
});