Android -- 动画
一,首先说一下,Android 项目中res下的anim 和 animtor 文件夹。
-
anim文件夹
anim文件夹下存放tween animation和frame animation;xml文件里只有scale、rotate、translate、alpha、set五个标签(默认的中心是View的左上角)
使用方法:
1. 加载动画:animation = AnimationUtils.loadAnimation(R.anim.xxx)
2. 设置动画:mView.setAnimation(animation)
3. 开启动画:mView.startAnimation()
-
animator文件夹
animator文件夹下存放property animation,即属性动画,xml文件里有animator、objectAnimator、set三个标签。
在XML中:
ObjectAnimator --对应--> <objectAnimator>
AnimatorSet --对应--> <set>
使用方法:
1. 加载动画:animation = AnimatorInflater.loadAnimator(R.animator.xxx)
2. 设置动画:animation.setTarget(mView)
3. 开启动画:animation .start()
二,视图动画(tween animation)
tween动画一共有四种动画效果:
- 平移动画 translate (xml) -->TranslateAnimation (java代码)
- 缩放动画 scale (xml) -->ScaleAnimation (java代码)
- 旋转动画 rotate (xml) -->RotateAnimation (java代码)
- 透明度动画 alpha (xml) -->AlphaAnimation (java代码)
tween 动画的坐标
tween 的坐标体系 ( ↓ Y正方向;→ X正方形)也是以目标 view 的坐标为参考的。以目标 view 的左上角为坐标原点。
xml中参数数值:
2,% 自身的%为单位
image.png3,%p 以父布局%为单位
image.png注意:tween动画,四种操作都不改变其view的属性。例如:给view添加点击事件,进行平移操作之后,该点击事件仍在原地。
三,属性动画(Property Animation) -- 通过动画的方式改变对象的属性了
1,ObjectAnimator: 常用方法有这些:ofFloat(),ofInt(),ofObject(),ofArgb(),ofPropertyValuesHolder()。
/**
* @param target 动画操作的对象(可以是任意对象)
* @param propertyName 表示操作对象的属性名字(只要是对象有的属性都可以),任何一切带有set开头的方法属性名字。
* 常用的有:
* 平移 translationX,translationY, X,Y
* 缩放 scaleX,scaleY
* 旋转 rotationX, rotationY
* 透明度 alpha。
* 也就是说控件都有以上setTranslationX(),setScaleX(),setRotationX(),setAlpha() 等方法。
* @param values 动画过渡值。当然过度值可以有一个到N个,如果是一个值的话默认这个值是动画过渡值的结束值。如果有N个值,动画就在这N个值之间过渡。
* @return An ObjectAnimator object that is set up to animate between the given values.
*/
ObjectAnimator ofFloat(Object target, String propertyName, float... values)
例如:
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.3f, 1.0F);
animator.setDuration(2000);//动画时间
animator.setInterpolator(new BounceInterpolator());//动画插值(有好多种)
animator.setRepeatCount(-1);//设置动画重复次数--无限次(ValueAnimator.INFINITE=-1)
animator.setRepeatMode(ValueAnimator.RESTART);//动画重复模式
animator.setStartDelay(1000);//动画延时执行
animator.start();//启动动画
2,组合动画 -- AnimatorSet
常见方法有:
- after(Animator anim) 将现有动画插入到传入的动画之后执行
- after(long delay) 将现有动画延迟指定毫秒后执行
- before(Animator anim) 将现有动画插入到传入的动画之前执行
- with(Animator anim) 将现有动画和传入的动画同时执行
//开始图片的透明度从不透明到0.2的透明再到不透明,随着整个布局背景的颜色变化的同时ImageView先向右平移200个像素,
//然后再放大2倍,最后沿着X轴从0到90度再到0度的旋转。
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);
//组合动画方式
AnimatorSet set = new AnimatorSet();
((set.play(animator).with(animator1).before(animator2)).before(animator3)).after(animator4);
set.setDuration(5000);
set.start();
3,动画监听器 -- 用来监听不同状态下的动画情况。
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 动画重复的操作
}
});
如果你不想都写上面的几个方法,只需要动画结束时的监听,可以这样:
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//TODO 动画结束的操作
}
});
AnimatorListenerAdapter的源码只是一个实现了AnimatorListener接口的抽象类而已,你需要监听哪种动画状态就重写哪种方法就可以了。
Android系统还给我们提供了一个更加精确的方法来时刻监听当前动画的执行情况。那就是addUpdateListener(AnimatorUpdateListener listener)方法了。调用该方法只需实现AnimatorUpdateListener接口就可以读取到动画的每个更新值了。
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
//获取动画更新值。
}
});
4,ValueAnimator
ValueAnimator是属性动画中的一个重要的类,其内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果我们通过例子来看看它的用法。ValueAnimator的用法很简单:
ValueAnimator animator = ValueAnimator.ofInt(0, 20,0);
//动画值的变化,0---> 20 ---->0,常用于自定义View中,值的变化
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
Log.e("TAG", "the value is " + value);
}
});
animator.setDuration(1000);//动画时间
animator.start();//启动动画
/**
* 当然,还有
* ValueAnimator.ofFloat(0f,10.5f,5.0f,0f);
* ValueAnimator.ofArgb(0x00ffff,0x00ffee);
* ValueAnimator.ofObject() // 比较重要,涉及到了估值器
*/
5,估值器 -- TypeEvaluator
动画过程中TypeEvaluator(估值器)的作用:当我们ValueAnimator.ofObject()函数来做动画效果的时候就会用到估值器了,估值器说白了就是用来确定在动画过程中每时每刻动画的具体值的;换句话说就是确定ValueAnimator.getAnimatedValue()返回的具体对象类型 ( 当我们使用ValueAnimator.ofObject()的时候,是一定要去设置估值器的 ) 。
所有的估值器都要实现TypeEvaluator接口,TypeEvaluator接口具体代码如下。
public interface TypeEvaluator<T> {
/**
* This function returns the result of linearly interpolating the start and end values, with
* <code>fraction</code> representing the proportion between the start and end values. The
* calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
* and <code>t</code> is <code>fraction</code>.
*
* @param fraction 表示当前这段数值变化值得比例
* @param startValue 当前这段数值变化的开始值
* @param endValue 当前这段数据变化的结束值。
* @return A linear interpolation between the start and end values, given the
* <code>fraction</code> parameter.
*/
public T evaluate(float fraction, T startValue, T endValue);
}
简单使用如下:
private void startAnimation() {
PointF startPointF = new PointF(0, 0);
PointF endPointF = new PointF(300, 300);
ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(), startPointF, endPointF);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//此处得到的返回值类型,由PointEvaluator 决定,为 PointF
PointF pointF = (PointF) animation.getAnimatedValue();
Log.d(TAG, "onAnimationUpdate: " + pointF.x);
x = pointF.x;
//不断的刷新UI
invalidate();
}
});
animator.setDuration(2000);
animator.start();
}
/**
* 自定义 ,估值器
*/
private class PointEvaluator implements TypeEvaluator<PointF> {
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
float resultX = startValue.x + fraction * (endValue.x - startValue.x);
float rexultY = startValue.y + fraction * (endValue.y - startValue.y);
Log.d(TAG, "evaluate: resultX= " + resultX + "\nrexultY=" + rexultY);
return new PointF(resultX, rexultY);
}
}
6,插值器 -- Interpolator
几种常用的集中插值器(以下图片源自网络):
- AccelerateDecelerateInterpolator开始与结束的地方速率改变比较慢,在中间的时候加速。
- AccelerateInterpolator开始的地方速率改变比较慢,然后开始加速。
-AnticipateInterpolator开始的时候向后然后向前甩
image.png四、Android 圆形揭露动画(API>21)
官方介绍
当您显示或隐藏一组UI元素时,显示动画可为用户提供视觉连续性。
/ * @param view 要隐藏或显示在屏幕上的视图View.
* @param centerX 剪切圆中心的x坐标
* @param centerY 剪切圆中心的y坐标
* @param startRadius 剪切圆的起始半径
* @param endRadius 圆的最终半径
*/
public static Animator createCircularReveal(View view,
int centerX, int centerY, float startRadius, float endRadius) {
return new RevealAnimator(view, centerX, centerY, startRadius, endRadius);
}
简单使用:
Button mRevealBtn = findViewById(R.id.reveal_btn);
int centerX = mRevealBtn.getWidth() / 2;
int centerY = mRevealBtn.getHeight() / 2;
//判断api是否大于21
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Animator mAnimator = ViewAnimationUtils.createCircularReveal(mRevealBtn, centerX, centerY, Math.max(centerX, centerY), 0);
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
//这里可以监听到动画完成的事件;
//可以在这里进行gone的操作
}
});
mAnimator.start();
}