动画
1. 补间动画
1.1 简介1.2 基本使用1.3 特殊场景使用1.4 高级使用 2. 插值器
2.1 基本介绍2.2 自定义插值器 3. 估值器
3.1 自定义估值器 4. 属性动画
4.1 ValueAnimator4.2 ValueAnimator实例说明4.3 ObjectAniamtor4.4 ObjectAnimator实例说明 5. 属性动画使用技巧
5.1 组合动画5.2 快捷使用5.3 监听动画5.4 动画适配器
Android动画分类
补间动画:提供开始结束数值和动画时间,系统自动生成中间动画逐帧动画:快速播放图片形成动画属性动画:通过不断修改控件属性形成动画效果 1. 补间动画 1.1 简介
分为平移translate、缩放scale、旋转rotate和透明度alpha
特点
优点:简单、方便缺点:仅仅控制整体效果,没法控制属性
使用场景
常规动画效果特殊应用场景:
Activity切换效果Fragment切换效果ViewGroup中子元素出场效果 1.2 基本使用
xml方式
- 在res/anim中创建动画效果xml文件
- Animation anim = AnimationUtils.loadAnimation(context, 动画文件)实现动画的控件.startAnimation(anim)
Java方式
- 实例相应的类平移TranslateAnimation、旋转RotateAnimation、缩放ScaleAnimation、透明度AlphaAnimation,其构造方法参数对应其标签的特有属性其他设置,比如anim.setDuration(3000)实现动画的控件.startAnimation(anim)
使用系统封装的动画效果
// Activity使用
public void onCreate(Bundle savedInstanceState) {
// 淡入 淡出
// ↓ ↓
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
super.onCreate(savedInstanceState);
}
public void finish() {
super.finish();
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
}
// Fragment使用
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.setTransition(FragmentTransaction.系统预设);
// TRANSIT_NONE 无动画
// TRANSIT_FRAGMNET_OPEN 标准打开动画效果
// TRANSIT_FRAGMNET_CLOSE 标砖关闭动画效果
ft.setCustomAnimations(R.anim.in_from_right, R.anim.out_to_left); // 自定义动画
注意:进入退出页面,一个需要动画、另一个不需要动画,也必须设置时间相同的、没有任何变化的动画,否则会出现黑屏
自定义效果 创建一个动画xml文件,然后如上使用
ViewGroup子元素动画
xml设置
- 设置子元素动画设置View Group动画文件
- 为ViewGroup指定android:layoutAniamtion属性
Java设置
- 加载子元素出场动画LayoutAnimationController controller = new LayoutAnimationController(anim)设置属性,比如controller.setDelay(0.5f)加载动画的Viewgroup.setLayoutAnimation(controller)
组合动画
xml:使用 设置属性值从初始值过度到结束之的变化规律(匀速、加速、减速等),实现非线性动画效果 内置插值器 根据动画进度计算出当前属性值改变的百分比 实现Interpolator或TimeInterpolater接口,重写getInterpolation()方法属性动画实现TimeInterpolater,用于兼容Interpolator接口,使得过去Interpolator实现列都可以直接用在属性动画中
设置属性值从开始值过度到结束值的变化具体数值 系统内置估值器 Intevaluator 以整型的形式进行过度Floatevaluator 以浮点型的形式进行过度Argbevaluator 以Argb类型的形式进行过度
3.1 自定义估值器
实现Typeevaluator接口,重写evaluate()方法 视图动画存在缺陷:作用对象局限(View)、仅改变视觉效果、动画效果单一 属性动画 可以作用于任意Java对象可以自定义动画效果
工作原理:不对对属性值进行修改,不断将值赋给对象属性 主要通过ValueAnimator和ObjectAnimator类实现 通过不断控制值的变化,再不断手动赋给对象属性 ValueAnimator.ofInt(int value) 内置估值器IntevaluatorValueAnimator.ofFloat(float value) 内置估值器FloatevaluatorValueAnimator.ofObject(int value)
xml设置 Java设置 ValueAnimator.ofObject() ValueAnimator anim = ValueAnimator.ofObject(new 自定义估值器, object1, object2) 需要自定义估值器 实现一个圆形从左上角移动到右下角 自定义估值器 将属性动画作用到自定义View当中 将自定义View放到布局中 ofObject()本质上还是操作值,只不过采用将多个值封装到一个对象中,对多个值一起操作 与ObjectAnimator区别 ValueAnimator不断改变值,手动赋值给对象的属性从而实现动画效果,间接对对象属性操作ObjectAnimator不断改变值,自动赋值给对象的属性从而实现动画效果,直接对对象属性操作
4.3 ObjectAniamtor
继承自ValueAnimator Java设置 xml设置 第二个参数作用是让ObjectAnimator类根据传入属性名去寻找改对象对应属性名的set()、get()方法,从而进行对象属性值的赋值 原理解析 采用ObjectAnimator实现动画效果,需要操作的对象就必须有该属性的get、set方法 实现一个圆形颜色渐变 设置对象类谁能够的set、get方法 直接法:继承原始类,直接加上该属性的get、set方法
该对象本身没有这个属性时,采用直接法 间接法:包赚原始动画对象,间接给对象加上该属性的get、set方法,即用一个类来包装原始对象
当属性存在set方法但set方法无法带来预期的UI变化时使用间接法
5. 属性动画使用技巧
5.1 组合动画
使用AnimatorSet类 play(anim) 播放当前动画after(delay) 将现有动画延迟x毫秒执行with(anim) 将现有动画和传入动画同时执行after(anim) 将现有动画插入到传入动画之后执行before(anim) …
xml设置:前面讲解过 ViewPropertyAnimator类 Animation类监听动画开始 / 结束 / 重复时的操作addListener()中设置
5.4 动画适配器
解决并不需要监听动画所有时刻的问题,解决实现接口繁琐问题
2.2 自定义插值器
作用 资源ID Java类 加速 @android:anim/accelerate_interpolator AccelerateInterpolator 快速完成,超出在回到结束样式 …overshoot… OvershootInterpolator 加速 -> 减速 …accelerate_decelerate… AccelerateDecelerateInterpolator 先退后在加速前进 …anticipate… AnticipateInterpolator 先退后在加速前进,超过终点再回到重点 …anticipate_overshoot… AnticipateOvershootInterpolator 最后阶段弹球效果 …bounce… BounceInterpolator 减速 …decelerate… DecelerateInterpolator 匀速 …linear… LinearInterpolator 周期运动 …cycle… CycleInterpolator public interface Interpolator {
float getInterpolator(float input) {
// input 变化范围(0~1),随动画进度均匀变化,开始为0,结束为1
return xxx; // 返回值用于估值器继续计算fraction值
}
}
// LinearInterpolator
return input;
// AccelerateDecelerateInterpolator
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
3. 估值器
public class Objectevaluator implements Typeevaluator{
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
// 参数说明
// fraction:表示动画完成度(根据它来计算当前动画的值),也是插值器getInterpolation()的返回值
// startValue:动画的初始值
// endValue:动画的结束值
// 返回对象动画过渡逻辑计算后的值
// 即赋给动画属性的具体数值
return value;
}
4. 属性动画
在res/animator创建动画xml文件
使用标签特有属性:valueFrom、valueTo、valueType(变化值类型,floatType & intType)公共属性和补间动画中相同
Animator animator = AnimatorInflater.loadAnimator(context, 动画xml)animator.setTarget(view) 设置动画对象animator.start()ValueAniamtor anim = ValueAnimator.toInt(0, 3)
public static ValueAnimator ofInt(int... values)
设置其他属性将改变的值手动赋值给对象的属性值,通过动画的更新监听器anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimaionUpdate(ValueAnimator animation) {
int currentValue = (Integer) animation.getAnimatedValue();
// 以按钮宽度改变为例
btn.getLayoutParams().width = currentValue;
btn.requestLayout(); // 刷新视图,重新绘制
}
})
anim.start()
// Point.kt
class Point(val x: Float, val y: Float);
// Pointevaluator.kt
class Pointevaluator : Typeevaluator
public class MyView extends View {
public static final float RADIUS = 70f;
private Point currentPoint;
private Paint mPaint;
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
}
protected void onDraw(Canvas canvas) {
if (currentPoint == null) {
currentPoint = new Point(RADIUS, RADIUS);
float x = currentPoint.getX();
float y = currentPoint.getY();
canvas.drawCircle(x, y, RADIUS, mPaint);
// 创建开始动画对象点和结束动画对象点
Point start = new Point(RADIUS, RADIUS);
Point end = new Point(700f, 1000f);
// 创建动画对象,设置初始值和结束值
ValueAnimator anim = ValueAnimator.ofObject(new Pointevaluator(), start, end);
anim.setDuration(5000);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint = (Point) animation.getAnimatedValue();
// 重新绘制
invalidate();
}
});
anim.start();
} else {
float x = currentPoint.getX();
float y = currentPoint.getY();
canvas.drawCircle(x, y, RADIUS, mPaint);
}
}
}
ObjectAnimator anim = ObjectAnimator.ofFloat(object, proprty, values)
Object object 操作对象String property 操纵的对象属性float… values 动画初始值 & 结束值ofObject还有一个参数是自定义估值器
其他设置anim.start()在res/animtor创建动画xml文件
使用
Animator anim = AnimatorInflater.loadAnimator(context, 动画xml文件)anim.setTraget(动画对象)anim.start()@Override
public void start() {
AnimationHandler handler = sAnimationHandler.get();
...
super.start();
// 调用父类的start()
// 因为ObjectAnimator类继承ValueAnimator类,所以调用的是ValueAnimator的star()
// 经过层层调用,最终会调用到 自动赋值给对象属性值的方法 ->关注1
}
// 步骤1:初始化动画值
private void setupValue(Object target, Keyframe kf) {
if (mProperty != null) {
kf.setValue(mProperty.get(target));
// 初始化时,如果属性的初始值没有提供,则调用属性的get()进行取值
}
kf.setValue(mGetter.invoke(target));
}
}
// 步骤2:更新动画值
// 当动画下一帧来时(即动画更新的时候),setAnimatedValue()都会被调用
void setAnimatedValue(Object target) {
if (mProperty != null) {
mProperty.set(target, getAnimatedValue());
// 内部调用对象该属性的set(),从而将新的属性值设置给对象属性
}
}
View.animate().xxx().xxx();
// ViewPropertyAnimator的功能建立在animate()上
// 调用animate()方法返回值是一个ViewPropertyAnimator对象,之后的调用的所有方法都是通过该实例完成
// 调用该实例的各种方法来实现动画效果
// ViewPropertyAnimator所有接口方法都使用连缀语法来设计,每个方法的返回值都是它自身的实例
// 因此调用完一个方法后可直接连缀调用另一方法,即可通过一行代码就完成所有动画效果
View.animate().alpha(0f).setDuration(5000).setInterpolator(new BounceInterpolator());
5.3 监听动画
// 动画适配器
// ↓
anim.addListener(new AnimatorListenerAdapter() {
public void onAnimationStart(Animator animation) {
// 只需要重写自己需要的动画时刻
}
})



