动画与图形——属性动画
概述
Android框架提供了两种动画系统:属性动画(在Android3.0中引进)以及视图动画。这两种动画系统都有变化的选择,但是总的来说,属性动画系统是更好的选擇,因为它更加灵活,并提供了更多的特性。
属性动画系统是一个强大的框架,它允许你动画几乎所有的东西。例如一个对象在屏幕中的位置,要动画多久,和动画之间的距值。
通常我们要操作的属性为:
rotationX、rotationY 旋转
scaleX、scaleY 缩放
translationX、translationY 平移
X、Y坐标
alpha透明度
ObjectAnimator
绕X轴旋转
ObjectAnimator.ofFloat(view,"rotationX",0.0f,360.0f).setDuration(1000).start();
组合多个动画
PropertyValuesHolder p1=PropertyValuesHolder.ofFloat("alpha",1f,0f,1f);
PropertyValuesHolder p2=PropertyValuesHolder.ofFloat("scaleX",1f,0f,1f);
PropertyValuesHolder p3=PropertyValuesHolder.ofFloat("scaleY",1f,0f,1f);
ObjectAnimator.ofPropertyValuesHolder(view,p1,p2,p3).setDuration(1000).start();
ValueAnimator
自由落体动画
public void fullClick(View view){
final View v=view;
DisplayMetrics dm=new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);//获取屏幕高度
//定义一个动画
ValueAnimator va=ValueAnimator.ofFloat(view.getY(),dm.heightPixels,view.getY(),0f).setDuration(1000);
//监听动画的每一个动作
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
v.setTranslationY((Float) animation.getAnimatedValue());
}
});
va.start();
}
监听动画事件
对于动画,一般都是一些辅助效果,比如我们要删除一个元素,我可能希望是个淡出的效果,但是最终还是要删掉,并不是你透明度没了,还占着位置,所有我们需要知道动画如何结束。
删除动画
final View v=view;
//监听动画事件
ObjectAnimator oa=ObjectAnimator.ofFloat(view,"alpha",1f,0f).setDuration(1000);
oa.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//动画结束
ViewGroup viewGroup= (ViewGroup) v.getParent();
if (viewGroup!=null){
viewGroup.removeView(v);
System.out.println("removed.");
}
}
});
oa.start();
AnimatorSet
AnimatorSet的使用
ObjectAnimator a1=ObjectAnimator.ofFloat(view,"translationX",0f,200f);
ObjectAnimator a2=ObjectAnimator.ofFloat(view,"translationY",0f,200f);
ObjectAnimator a3=ObjectAnimator.ofFloat(view,"rotation",0f,360f);
AnimatorSet set=new AnimatorSet();
set.setDuration(1000);
set.playTogether(a1,a2,a3);//三个动画同时执行
// set.setStartDelay(300);//延迟执行
// set.playSequentially(a1,a2,a3);//顺序执行
//自定义组合执行
// set.play(a1);//单独执行
// set.play(a1).with(a2);//a1,a2一起执行
// set.play(a3).after(a2);//a3在a2之后执行
set.start();
注意:
animSet.play().with();也是支持链式编程的,但是:animSet.play(a1).with(a2).before(a3).before(a5);这样是不行的,系统不会根据你写的这一长串来决定先后
插值器(Interpolators)
例如: set.setinterpolator(new Bouncelnterpolator());
AccelerateDeceleratelnterpolator——插补, 其变化率慢慢开始和结束,但通过中间加速。
Accelerateinterpolator——插补, 其变化率开始缓慢,然后加快。
Anticipatelnterpolator——内插的变化 开始落后,然后向前甩。
AnticipateOvershootinterpolator——内插的变化, 开始落后,甩向前过冲目标值,然后终于可以追溯到最终值。
Bouncelnterpolator——插补, 其变化在最后反弹。
Cyclelnterpolator——内插动画 重复指定的周期数。
Decelerateinterpolator——插补, 其变化的速度开始很快,然后减速。
Linearlnterpolator——插补, 其变化率是恒定的
Overshootinterpolator——内插的变化甩向前和过冲的最后一个值,然后回来。
Timelnterpolator——一个接口,使您实现自己的插补。
使用XML文件来创建属性动画
在res资源文件下创建animator资源文件夹
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator android:duration="3000"
android:propertyName="alpha"
android:valueFrom="1.0"
android:valueTo="0.0"/>
</set>
加载动画
Animator a=AnimatorInflater.loadAnimator(this,R.animator.animator);
a.setTarget(view);
a.start();
多个动画组合
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator android:duration="1000" android:propertyName="scaleX"
android:valueFrom="0.0" android:valueTo="1.0"/>
<objectAnimator android:duration="1000" android:propertyName="scaleY"
android:valueFrom="0.0" android:valueTo="1.0"/>
</set>
动画菜单案例
package com.example.animateandview;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.BounceInterpolator;
import android.widget.ImageView;
import android.widget.Toast;
import java.util.ArrayList;
public class Main3Activity extends AppCompatActivity implements View.OnClickListener {
private int[] res={
R.id.imageView3,
R.id.imageView4,
R.id.imageView5,
R.id.imageView6,
R.id.imageView7,
R.id.imageView8,
R.id.imageView9,
R.id.imageView10
};
private ArrayList<ImageView> list=new ArrayList<>();
private boolean isOpen=false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
for (int i=0;i<res.length;i++){
ImageView imageView=findViewById(res[i]);
imageView.setOnClickListener(this);
list.add(imageView);
}
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.imageView3:
if (isOpen){
closeMenu();
isOpen=false;
}else{
openMenu();
isOpen=true;
}
break;
default:
Toast.makeText(this, v.getTag().toString(), Toast.LENGTH_SHORT).show();
break;
}
}
//关闭菜单
private void closeMenu(){
for (int i=1;i<res.length;i++){
ObjectAnimator a1=ObjectAnimator.ofFloat(list.get(i),"translationX",100*i,0);
ObjectAnimator a2=ObjectAnimator.ofFloat(list.get(i),"translationY",100*i,0);
AnimatorSet set=new AnimatorSet();
set.setDuration(1000);
set.setInterpolator(new BounceInterpolator());
set.playTogether(a1,a2);
set.start();
}
}
//打开菜单
private void openMenu(){
for (int i=1;i<res.length;i++){
ObjectAnimator a1=ObjectAnimator.ofFloat(list.get(i),"translationX",0,100*i);
ObjectAnimator a2=ObjectAnimator.ofFloat(list.get(i),"translationY",0,100*i);
AnimatorSet set=new AnimatorSet();
set.setDuration(1000);
set.setInterpolator(new BounceInterpolator());
set.playTogether(a1,a2);
set.start();
}
}
}