android动画 -- Property Animator
属性动画原理
根据时间的推移,Property Animation改变组件view的实际动作属性,从而完成动画效果;在组件开始动画之前必须满足一个条件,就是必须要提供组件的setX和getX方法,因为属性动画会根据你传入的propertyName,如下“width”,它会去你的mButton里面去找setWidth方法,如果你的propertyName不对,它会包找不到setPropertName这个方法,无法完成动画;
但是如果你使用Button来做动画效果时,如下代码:
ObjectAnimator.ofInt(mButton, "width", 500).setDuration(5000).start();
发现它根本就没有动画效果,这是因为Button是继承TextView的,虽然提供了setWidth和getWidth方法,但是TextView的setWidth根本不是改变组件的宽度值,其源码如下:
@android.view.RemotableViewMethod
public void setWidth(int pixels) {
mMaxWidth = mMinWidth = pixels;
mMaxWidthMode = mMinWidthMode = PIXELS;
requestLayout();
invalidate();
}
所以,在我们使用一些组件的时候,如果动画效果不发生改变的话,建议对组件进行封装一下,执行提供set和get方法,如下方案:
private static class ViewWrapper{
View mTarget;
public ViewWrapper(View target){
mTarget = target;
}
public int getWidth(){
return mTarget.getLayoutParams().width;
}
public void setWidth(int width){
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
}
Button btn = (Button)findViewById(R.id.btn);
final ViewWrapper wrapper = new ViewWrapper(btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
ObjectAnimator.ofInt(wrapper , "width", 500).setDuration(5000).start();
}
});
这样就能正确完成动画效果了;从上面也可以看出,属性动画就是在动画过程中改变组件的状态值,从而完成动画效果,下面讲讲动画的使用;
ObjectAnimator 动画的执行类
ObjectAnimator 可以直接作用在组件上,根据设置的动画的各个状态值完成动画,使用方法超级简单,看范例即可:
TextView tv = (TextView)findViewById(R.id.text);
ObjectAnimator.ofInt(tv, "width", 0, 500).setDuration(5000).start();
ObjectAnimator.ofInt(tv, "width", 0, 500).setDuration(5000).start();
注意第二个参数width,动画过程中它会去找setWidth,所以你必须填写对
ValueAnimator
ValueAnimator 不能直接作用在view组件上,它用于状态的模拟,也就是组件从一个状态变化到另一个状态,模拟出中间的每个状态值,组件再把这个状态值设置到自身上去,从而实现动画效果,看使用范例:
public void animatorTest(final View view){
ValueAnimator animator = ValueAnimator.ofInt(view.getLayoutParams().width,view.getLayoutParams().width + 100);
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator arg0) {
// TODO Auto-generated method stub
Integer i = (Integer)arg0.getAnimatedValue();
Log.i("jackzhous", "i = " + i);
view.getLayoutParams().width = i;
view.requestLayout();
}
});
animator.setDuration(1000).start();
}
设置监听,更新状态即可;
组合动画
组合动画也就是将上面几个动画加在一起一块执行;方法有三种
使用AnimatorSet
//设置多组ObjectAnimator对象动画效果;设置他们的动画先后关系*/
ObjectAnimator anim1 = ObjectAnimator.ofFloat(v, "scal", 1f, 0.0f).setDuration(1000);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(v, "scaleY", 1f, 0.0f).setDuration(1000);
ObjectAnimator anim3 = ObjectAnimator.ofFloat(v, "alpha", 1f, 0.0f).setDuration(1000);
AnimatorSet aS = new AnimatorSet();
aS.play(anim1).with(anim2);
aS.play(anim2).with(anim3);
aS.start();
使用ObjectAnimator 时,同时增加更新监听
每一帧图像刷新的时候就调用下面的监控函数,在里面我们去设置那个值就可以了
ObjectAnimator anim = ObjectAnimator.ofFloat(v, "scal", 1f, 0.0f).setDuration(1000);
anim.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator arg0) {
// TODO Auto-generated method stub
float value = (Float) arg0.getAnimatedValue();
v.setAlpha(value);
v.setScaleX(value);
v.setScaleY(value);
Log.i(TAG, "onAnimationUpdate");
}
});
anim.start();
通过PropertyValuesHolder设置动画属性,将属性添加到ObjectAnimator里面去即可
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 0.0f, 1.0f);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 0.0f, 1.0f);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 0.0f, 1.0f);
ObjectAnimator.ofPropertyValuesHolder(v, holder1, holder2, holder3).setDuration(5000).start();
}
动画监听
有时候我们需要监听动画过程的每个状态,从而执行相应的动作,属性动画为我们提供了监听,
animator.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator arg0) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animator arg0) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator arg0) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationCancel(Animator arg0) {
// TODO Auto-generated method stub
}
});
XML方式使用动画:
在res/anim下创建xml文件
<?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="1"
android:valueTo="0.5" >
</objectAnimator>
<objectAnimator
android:duration="1000"
android:propertyName="scaleY"
android:valueFrom="1"
android:valueTo="0.5" >
</objectAnimator>
</set>
Java代码中读取:
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scale); //利用AnimatorInflater读取xml文件
mMv.setPivotX(0);
mMv.setPivotY(0);
//显示的调用invalidate
mMv.invalidate();
anim.setTarget(mMv); //设置对象
anim.start();
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】