动画的分类
动画分为视图动画(View)和属性动画(Property),而视图动画又分为Tween动画和Frame动画,属性动画又分为ValueAnimator和ObjectAnimator.
属性动画简介
从Android3.0开始出现,真实改变View的属性,可以响应事件
使用ObjectAnimator时,对象的属性必须有get和set方法,因为内部会通过反射来调用属性的set方法,如果一个属性没有get和set方法,可以通过下面两种方式来解决。
1.自定义一个属性类或者包装类
2.使用ValueAnimator
public class WrapperView {
private View mTargetView;
public WrapperView(View targetView){
mTargetView = targetView;
}
public int getWidth(){
return mTargetView.getLayoutParams().width;
}
public void setWidth(int width){
mTargetView.getLayoutParams().width = width;
mTargetView.requestLayout();
}
}
public class MainActivity extends AppCompatActivity {
private WrapperView wrapperView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.button);
wrapperView = new WrapperView(btn);
}
public void click(View view){
ObjectAnimator.ofInt(wrapperView,"width",0,500).setDuration(5000).start();
}
}
在属性动画中,使用PropertyValueHolder可以使多个动画共同作用,用法类似于AnimationSet的使用。
ValueAnimator
本身不提供任何动画效果,更像一个数值发生器,用来产生一定规律的数字,从而让调用者控制动画的实现过程。用法如下
//创建对象
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1);
//设置要添加动画的view
valueAnimator.setTarget(btn);
valueAnimator.setDuration(4000);
//启动动画
valueAnimator.start();
//添加监听
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//不断获取动画过程中的值
float animatedValue = (float) animation.getAnimatedValue();
btn.setAlpha(animatedValue);
}
});
AnimatorSet也可以对一个属性进行多个动画,还能控制顺序,比前面的PropertyValueHolder更强大。
View的animate方法
在API16之后,提供了animate方法直接驱动属性动画
btn.animate().alpha(0).y(200).setDuration(2000)
.withStartAction(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "开始", Toast.LENGTH_SHORT).show();
}
}).withEndAction(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "结束", Toast.LENGTH_SHORT).show();
}
});
}
布局动画
布局动画是指作用在ViewGroup上,给ViewGroup添加View时增加一个动画效果。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ll = (LinearLayout) findViewById(R.id.ll);
TranslateAnimation animation = new TranslateAnimation(720,0,0,0);
animation.setDuration(2000);
LayoutAnimationController controller = new LayoutAnimationController(animation,0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
ll.setLayoutAnimation(controller);
addView();
}
public void addView(){
for (int i = 0; i < 10; i++) {
TextView textView = new TextView(this);
textView.setText("文字"+i);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams
(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ll.addView(textView,params);
}
}
自定义动画
步骤:
1.重写initialize方法做初始化动作
2.重写applyTransformation方法
public class RotateAnim extends Animation {
private int mCenterWidth;
private int mCenterHeight;
private Camera camera = new Camera();
private float mRotateY = 0.0f;
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
setDuration(2000);
setFillAfter(true);
setInterpolator(new BounceInterpolator());
mCenterWidth = width/2;
mCenterHeight = height/2;
}
public void setRotateY(float rotateY){
mRotateY = rotateY;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
Matrix matrix = t.getMatrix();
camera.save();
camera.rotateY(mRotateY*interpolatedTime);
camera.getMatrix(matrix);
camera.restore();
//设置旋转中心,
matrix.preTranslate(mCenterWidth/2,mCenterHeight);
matrix.postTranslate(-mCenterWidth/2,-mCenterHeight);
}
}
Android 5.X SVG 矢量动画机制
SVG是可伸缩矢量图形,使用XML格式定义图形,图像在放大或者改变尺寸的情况下图像质量不会有损失。
Android中使用SVG需要使用下面两个API
VectorDrawable:创建基于XML的SVG图形
AnimatedVerctorDrawable:实现动画效果,比喻为一个胶水,连接静态的VectorDrawable和动态的objectAnimator
动画特效
public class MainActivity extends AppCompatActivity {
private LinearLayout hiddenView;
private LinearLayout ll;
private boolean flag = false;
private float density;
private int hiddenViewHeight;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
density = getResources().getDisplayMetrics().density;
hiddenViewHeight = (int) (density*40+0.5f);
ll = (LinearLayout) findViewById(R.id.ll);
hiddenView = (LinearLayout) findViewById(R.id.hiddenView);
ll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(hiddenView.getVisibility() == View.GONE){
hiddenView.setVisibility(View.VISIBLE);
ValueAnimator animator = createAnimation(hiddenView, 0, hiddenViewHeight);
animator.start();
}else{
int oriHeight = hiddenView.getHeight();
ValueAnimator animator = createAnimation(hiddenView, oriHeight, 0);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
hiddenView.setVisibility(View.GONE);
}
});
animator.start();
}
}
});
}
public ValueAnimator createAnimation(final View view, int start, int end){
ValueAnimator animator = ValueAnimator.ofInt(start,end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
params.height = (int) animation.getAnimatedValue();
view.setLayoutParams(params);
}
});
flag = true;
return animator;
}
}