属性动画
DEMO地址:https://github.com/chaozhouzhang/CustomProgressView
1、值动画 ValueAnimator
值动画具体实现步骤:
/**
* 属性动画之值动画:
* 1、指定动画数值区间
* 2、指定插值器,定义动画数值的进度变化规律
* 3、指定估值器,根据插值器的进度变化规律,计算具体的动画数值
* 4、设置监听器,监听估值器返回的具体动画数值,然后根据此具体数值,来对控件做出属性变化的设置操作
*/
使用值动画,实现抛物动画:
ValueAnimator animator = ValueAnimator.ofObject(new FallingBallEvaluator(),new Point(0,0),new Point(500,500));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mPoint = (Point) animation.getAnimatedValue();
mIvBall.layout(mPoint.x,mPoint.y,mPoint.x+mIvBall.getWidth(),mPoint.y+mIvBall.getHeight());
}
});
animator.setDuration(2000);
animator.start();
DEMO地址:https://github.com/chaozhouzhang/CustomProgressView/blob/master/CustomProgressView/app/src/main/java/androidstack/progress/animation/property/value/FallingBallValueActivity.java
2、对象动画 ObjectAnimator
对象动画具体实现步骤:
/**
* 属性动画之对象动画:
* 1、指定动画数值区间以及属性和控件
* 2、指定插值器,定义动画数值的进度变化规律
* 3、指定估值器,根据插值器的进度变化规律,计算具体的动画数值
* 4、系统自定调用控件的set方法,根据属性拼装set方法并反射调用,并将当前值作为参数传入
*/
自定义ImageView:
public class FallingImageView extends androidx.appcompat.widget.AppCompatImageView {
public FallingImageView(Context context) {
super(context);
}
public FallingImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FallingImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 对象动画会使用反射自动调用此set方法
* @param point
*/
public void setFallingPos(Point point){
layout(point.x,point.y,point.x+getWidth(),point.y+getHeight());
}
/**
* 当指定一个动画值时,动画会通过get方法来获取初始值,否则会崩溃
* @return
*/
public Point getFallingPos(){
return new Point(0,0);
}
}
使用值动画,实现抛物动画:
ObjectAnimator objectAnimator = ObjectAnimator.ofObject(mIvBall,"fallingPos",new FallingBallEvaluator(),new Point(0,0),new Point(500,500));
objectAnimator.setDuration(2000);
objectAnimator.start();
DEMO地址:https://github.com/chaozhouzhang/CustomProgressView/blob/master/CustomProgressView/app/src/main/java/androidstack/progress/animation/property/object/FallingBallObjectActivity.java
3、动画集合 AnimatorSet
使用动画集合实现菜单动画:
开:
private void menuOpen(View view, int currIndex, int totalIndex, int radius) {
//每一份角度
double degree = Math.toRadians(90) / (totalIndex - 1) * currIndex;
//X轴移动距离
int translationX = -(int) (radius * Math.sin(degree));
//Y轴移动距离
int translationY = -(int) (radius * Math.cos(degree));
AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator objectAnimatorTranslationX = ObjectAnimator.ofFloat(view, "translationX", 0, translationX);
ObjectAnimator objectAnimatorTranslationY = ObjectAnimator.ofFloat(view, "translationY", 0, translationY);
ObjectAnimator objectAnimatorScaleX = ObjectAnimator.ofFloat(view, "ScaleX", 0F, 1F);
ObjectAnimator objectAnimatorScaleY = ObjectAnimator.ofFloat(view, "ScaleY", 0F, 1F);
ObjectAnimator objectAnimatorAlpha = ObjectAnimator.ofFloat(view, "alpha", 0F, 1F);
animatorSet.playTogether(objectAnimatorTranslationX, objectAnimatorTranslationY, objectAnimatorScaleX, objectAnimatorScaleY, objectAnimatorAlpha);
animatorSet.setDuration(500);
animatorSet.start();
}
关:
private void menuClose(View view, int currIndex, int totalIndex, int radius) {
//每一份角度
double degree = Math.PI * currIndex /((totalIndex-1)*2);
//X轴移动距离
int translationX = -(int) (radius * Math.sin(degree));
//Y轴移动距离
int translationY = -(int) (radius * Math.cos(degree));
AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator objectAnimatorTranslationX = ObjectAnimator.ofFloat(view, "translationX", translationX, 0);
ObjectAnimator objectAnimatorTranslationY = ObjectAnimator.ofFloat(view, "translationY", translationY, 0);
ObjectAnimator objectAnimatorScaleX = ObjectAnimator.ofFloat(view, "ScaleX", 1F, 0F);
ObjectAnimator objectAnimatorScaleY = ObjectAnimator.ofFloat(view, "ScaleY", 1F, 0F);
ObjectAnimator objectAnimatorAlpha = ObjectAnimator.ofFloat(view, "alpha", 1F, 0F);
animatorSet.playTogether(objectAnimatorTranslationX, objectAnimatorTranslationY, objectAnimatorScaleX, objectAnimatorScaleY, objectAnimatorAlpha);
animatorSet.setDuration(500);
animatorSet.start();
}
DEMO地址:https://github.com/chaozhouzhang/CustomProgressView/blob/master/CustomProgressView/app/src/main/java/androidstack/progress/animation/property/set/MenuActivity.java
4、属性值与关键帧 PropertyValuesHolder Keyframe
/**
* 关键帧,为了方便控制动画速率,表示某个时间点应该在某个位置上
* 视频,1秒要播24帧图片
* 一个关键帧的两个元素:时间点和位置
* fraction 动画进度
* value 对应动画进度的动画数值
* KeyFrame可以设置插值器,默认使用线性插值器
* 可以做电话响铃的动画,一张电话图片,11张关键帧
*/
使用属性值和关键帧实现电话铃响动画:
//旋转效果,左右震动
Keyframe keyframe1 = Keyframe.ofFloat(0f, 0);
Keyframe keyframe2 = Keyframe.ofFloat(0.1f, -20f);
Keyframe keyframe3 = Keyframe.ofFloat(0.2f, 20f);
Keyframe keyframe4 = Keyframe.ofFloat(0.3f, -20f);
Keyframe keyframe5 = Keyframe.ofFloat(0.4f, 20f);
Keyframe keyframe6 = Keyframe.ofFloat(0.5f, -20f);
Keyframe keyframe7 = Keyframe.ofFloat(0.6f, 20f);
Keyframe keyframe8 = Keyframe.ofFloat(0.7f, -20f);
Keyframe keyframe9 = Keyframe.ofFloat(0.8f, 20f);
Keyframe keyframe10 = Keyframe.ofFloat(0.9f, -20f);
Keyframe keyframe11 = Keyframe.ofFloat(1.0f, 0f);
PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",
keyframe1, keyframe1, keyframe2, keyframe3, keyframe4, keyframe5,
keyframe6, keyframe7, keyframe8, keyframe9, keyframe10, keyframe11);
//缩放效果 X
Keyframe keyframeScaleX0 = Keyframe.ofFloat(0,1f);
Keyframe keyframeScaleX1 = Keyframe.ofFloat(0.1f,1.1f);
Keyframe keyframeScaleX9 = Keyframe.ofFloat(0.9f,1.1f);
Keyframe keyframeScaleX10 = Keyframe.ofFloat(1f,1f);
PropertyValuesHolder propertyValuesHolderScaleX = PropertyValuesHolder.ofKeyframe("ScaleX",
keyframeScaleX0,keyframeScaleX1,keyframeScaleX9,keyframeScaleX10);
//缩放效果 Y
Keyframe keyframeScaleY0 = Keyframe.ofFloat(0,1f);
Keyframe keyframeScaleY1 = Keyframe.ofFloat(0.1f,1.1f);
Keyframe keyframeScaleY9 = Keyframe.ofFloat(0.9f,1.1f);
Keyframe keyframeScaleY10 = Keyframe.ofFloat(1f,1f);
PropertyValuesHolder propertyValuesHolderScaleY = PropertyValuesHolder.ofKeyframe("ScaleY",
keyframeScaleY0,keyframeScaleY1,keyframeScaleY9,keyframeScaleY10);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(mIvPhone,
propertyValuesHolder,propertyValuesHolderScaleX,propertyValuesHolderScaleY);
objectAnimator.setDuration(1000);
objectAnimator.start();
DEMO地址:https://github.com/chaozhouzhang/CustomProgressView/blob/master/CustomProgressView/app/src/main/java/androidstack/progress/animation/property/advanced/PhoneActivity.java
5、布局动画 LayoutTransition
/**
* LayoutTransition.APPEARING;新元素在容器中出现时的动画;
* LayoutTransition.CHANGE_APPEARING;容器中显示新元素,其他元素需要变化时的动画;
* LayoutTransition.CHANGE_DISAPPEARING;容器中移除旧元素,其他元素需要变化时的动画;
* LayoutTransition.CHANGING;
* LayoutTransition.DISAPPEARING;旧元素在容器中移除时的动画;
*/
实现移除布局内控件的动画:
/**
* 设置移除容器内图片控件时候的动画
*/
LayoutTransition layoutTransition = new LayoutTransition();
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);
layoutTransition.setAnimator(LayoutTransition.DISAPPEARING, objectAnimator);
/**
* 设置动画间的间隔
*/
layoutTransition.setStagger(LayoutTransition.DISAPPEARING, 1000);
mClLayoutTransition.setLayoutTransition(layoutTransition);
/**
* 移除布局
*/
mClLayoutTransition.removeView(mIvTest);
DEMO地址:https://github.com/chaozhouzhang/CustomProgressView/blob/master/CustomProgressView/app/src/main/java/androidstack/progress/animation/property/advanced/ViewGroupAnimateActivity.java
6、估值器 Evaluator
估值器,根据插值器的数值进度变化规律,计算出具体的动画数值。
自定义估值器,实现类型估值器TypeEvaluator,并传入泛型的具体类型。
扩展:
自定义插值器,实现时间插值器TimeInterpolator后,实现获取插值Interpolation的方法,也可以直接实现插值器Interpolator,因为Interpolator继承的是时间插值器TimeInterpolator。
自定义估值器:
public class ReverseEvaluator implements TypeEvaluator {
/**
* @param fraction 插值器中的进度返回值
* @param startValue 动画数值区间的起始数值
* @param endValue 动画数值区间的结束数值
* @return 估值器返回给监听器的具体动画数值
*/
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {return (int) (endValue - fraction * (endValue - startValue));
}
}
DEMO地址:https://github.com/chaozhouzhang/CustomProgressView/blob/master/CustomProgressView/app/src/main/java/androidstack/progress/animation/property/evaluator/ReverseEvaluator.java
欢迎关注微信公众号,Android技术堆栈: