支持:https://www.cnblogs.com/whoislcj/p/5738478.html

前言

ObjectAnimator是ValueAnimator的子类,但ValueAnimator有个缺点,就是只能对数值对动画计算。我们要想对哪个控件操作,需要监听动画过程,在监听中对控件操作。这样使用起来相比补间动画而言就相对比较麻烦。 为了能让动画直接与对应控件相关联,以使我们从监听动画过程中解放出来,谷歌的开发人员在ValueAnimator的基础上,又派生了一个类ObjectAnimator; 由于ObjectAnimator是派生自ValueAnimator的,所以ValueAnimator中所能使用的方法,在ObjectAnimator中都可以正常使用。

translationX的效果:

    protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_view_demo);
view2 = (MyView_1)findViewById(R.id.MyView2);
//传入float数组可以根据float数组里的值分别移动,注意!里面的值只是移动多少增量值,不是坐标值
float [] f = new float[]{100,-100,0};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"translationX",f);
//持续时间
objectAnimatorA.setDuration(3000);
objectAnimatorA.start();

translationY的效果:

    float [] f = new float[]{100,-100,0};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"translationY",f);
objectAnimatorA.setDuration(3000);
objectAnimatorA.start();

translationX+translationY的效果:

 float [] f = new float[]{100,-100,0};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"translationX",f);
objectAnimatorA.setDuration(3000);
objectAnimatorA.start();
ObjectAnimator objectAnimatorB = ObjectAnimator.ofFloat(view2,"translationY",f);
objectAnimatorB.setDuration(3000);
objectAnimatorB.start();

rotation的效果:

     float [] f = new float[]{90,-90,45};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"rotation",f);
objectAnimatorA.setDuration(3000);
objectAnimatorA.start();

rotationX的效果:

     float [] f = new float[]{90,-90,45};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"rotationX",f);
objectAnimatorA.setDuration(3000);
objectAnimatorA.start();

rotationY的效果:

     float [] f = new float[]{90,-90,45};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"rotationY",f);
objectAnimatorA.setDuration(3000);
objectAnimatorA.start();

rotation+rotationX的效果:

    float [] f = new float[]{90,-90,45};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"rotation",f);
objectAnimatorA.setDuration(3000);
objectAnimatorA.start();
ObjectAnimator objectAnimatorB = ObjectAnimator.ofFloat(view2,"rotationX",f);
objectAnimatorB.setDuration(3000);
objectAnimatorB.start();

rotation+rotationY的效果:

    float [] f = new float[]{90,-90,45};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"rotation",f);
objectAnimatorA.setDuration(3000);
objectAnimatorA.start();
ObjectAnimator objectAnimatorB = ObjectAnimator.ofFloat(view2,"rotationY",f);
objectAnimatorB.setDuration(3000);
objectAnimatorB.start();

rotationX+rotationY的效果:

    float [] f = new float[]{100,-100,0};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"rotationX",f);
objectAnimatorA.setDuration(3000);
objectAnimatorA.start();
ObjectAnimator objectAnimatorB = ObjectAnimator.ofFloat(view2,"rotationY",f);
objectAnimatorB.setDuration(3000);
objectAnimatorB.start();

setPivotX 和 setPivotY 的效果:

 view2 = (MyView_1)findViewById(R.id.MyView2);
//float [] f = new float[]{-180,180};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"rotation",360);
//参数是 100% 等于 1 ,90% 等于0.9 , 300%等于3(当然如果设置300% 坐标将远离View,会将View画更大的圈)
view2.setPivotX(1);
view2.setPivotY(1);
//view2.setPivotX(view2.getWidth()/2); 另一种写法可以更精确的设置view的支点
//view2.setPivotY(view2.getHeight());
objectAnimatorA.setDuration(3000);
objectAnimatorA.start();

scaleX 的效果:

view2 = (MyView_1)findViewById(R.id.MyView2);
float [] f = new float[]{1,3f};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"scaleX",f);
//ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"scaleX",1,3f); 直接这样写也可以
objectAnimatorA.setDuration(3000);
objectAnimatorA.start();

scaleY 的效果:

 view2 = (MyView_1)findViewById(R.id.MyView2);
float [] f = new float[]{1,3f};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"scaleY",f);
objectAnimatorA.setDuration(3000);
objectAnimatorA.start();

scaleX + scaleY 的效果:

view2 = (MyView_1)findViewById(R.id.MyView2);
float [] f = new float[]{1,3f};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"scaleX",f);
objectAnimatorA.ofFloat(view2,"scaleY",f);
objectAnimatorA.setDuration(3000);
objectAnimatorA.start();
ObjectAnimator objectAnimatorB = ObjectAnimator.ofFloat(view2,"scaleY",f);
objectAnimatorB.ofFloat(view2,"scaleY",f);
objectAnimatorB.setDuration(3000);
objectAnimatorB.start();

alpha 的效果:

    view2 = (MyView_1)findViewById(R.id.MyView2);
float [] f = new float[]{1,0f,1};
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"alpha",f);
objectAnimatorA.setDuration(5000);
objectAnimatorA.start();

x 和 y 的效果:

//y 和 translationY 的区别是 y 属性是直接移动到y的坐标点上,
// 而 translationX 是增量值,意思是需要移动多少
view2 = (MyView_1)findViewById(R.id.MyView2);
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"y",700);
objectAnimatorA.setDuration(5000);
objectAnimatorA.start();
ObjectAnimator objectAnimatorB = ObjectAnimator.ofFloat(view2,"x",500);
objectAnimatorB.setDuration(5000);
objectAnimatorB.start();

setStartDelay(long startDelay) 延迟动画启动效果:

view2 = (MyView_1)findViewById(R.id.MyView2);
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"translationX",500);
objectAnimatorA.setDuration(5000);
//延迟两秒启动动画
objectAnimatorA.setStartDelay(2000);
//不要忘记启动动画
objectAnimatorA.start();

setStartDelay(long startDelay) 延迟动画,动画分段效果:

view2 = (MyView_1)findViewById(R.id.MyView2);
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"translationX",500);
objectAnimatorA.setDuration(5000);
objectAnimatorA.start();
ObjectAnimator objectAnimatorB = ObjectAnimator.ofFloat(view2,"translationY",700);
objectAnimatorB.setDuration(5000);
objectAnimatorB.setStartDelay(5000);
objectAnimatorB.start();

setInterpolator(TimeInterpolator value)  的一系列效果:

功能说明:

setInterpolator方法是改变动画所使用的时间插值器,通俗的讲就是在不同时间点上改变动画的播放速度和动画效果

使用系统自带的 new BounceInterpolator() 效果(掉落回弹):

view2 = (MyView_1)findViewById(R.id.MyView2);
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"translationY",800);
objectAnimatorA.setDuration(5000);
objectAnimatorA.setInterpolator(new BounceInterpolator());
objectAnimatorA.start();

使用系统自带的 new AccelerateInterpolator() 效果(先慢后快):

view2 = (MyView_1)findViewById(R.id.MyView2);
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"translationY",800);
objectAnimatorA.setDuration(5000);
//objectAnimatorA.setInterpolator(new AccelerateInterpolator()); 可以不加参数
//参数是让下掉效果速度改变
objectAnimatorA.setInterpolator(new AccelerateInterpolator(3f));
objectAnimatorA.start();

使用系统自带的new DecelerateInterpolator() 的效果(先快后慢):

    view2 = (MyView_1)findViewById(R.id.MyView2);
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"translationY",800);
objectAnimatorA.setDuration(5000);
objectAnimatorA.setInterpolator(new DecelerateInterpolator(3f));
objectAnimatorA.start();

使用系统自带的 new AnticipateOvershootInterpolator() 的效果(先小幅度向上在正常播放然后在放大,在回正):

看了这么多移动的效果,我们看看放大的效果是什么样子的:

    view2 = (MyView_1)findViewById(R.id.MyView2);
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"scaleX",1,3f);
objectAnimatorA.setDuration(5000);
objectAnimatorA.setInterpolator(new AnticipateOvershootInterpolator(2f));
objectAnimatorA.start();
ObjectAnimator objectAnimatorB = ObjectAnimator.ofFloat(view2,"scaleY",1,3f);
objectAnimatorB.setDuration(5000);
objectAnimatorB.setInterpolator(new AnticipateOvershootInterpolator(2f));
objectAnimatorB.start();

使用系统自带的 new CycleInterpolator() 的效果(循环):

        view2 = (MyView_1)findViewById(R.id.MyView2);
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"translationY",200);
objectAnimatorA.setDuration(5000);
objectAnimatorA.setInterpolator(new CycleInterpolator(2f));
objectAnimatorA.start();

自定义Interpolator:

Interpolator还有很多不单单是上面这些效果,还有更多其他效果,你可以逐一去体验。系统自带的效果基本上可以满足正常使用,当然除了使用系统自带的还能自己写Interpolator。但是,对数学能力就有要求了,牛逼的大神可以就可以自己试试写Interpolator效果:

第一种写法:

直接自写一个类,继承Interpolator ,然后重写getInterpolation方法就可以了。然后使用的时候直接将自写的class实例化,添加到setInterpolator(里面) 就可以了。

第二种写法:

直接new 写内部类重写方法:

 view2 = (MyView_1)findViewById(R.id.MyView2);
ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(view2,"translationY",600);
objectAnimatorA.setDuration(5000);
objectAnimatorA.setInterpolator(new Interpolator() {
@Override
public float getInterpolation(float input) {
float result;
if (input <= 0.5) {
result = (float) (Math.sin(Math.PI * input)) / 2;
} else {
result = (float) (2 - Math.sin(Math.PI * input)) / 2;
}
return result;
}
});
objectAnimatorA.start();
}
 

动画组合、背景颜色渐变效果图:

         view2 = (MyView_1)findViewById(R.id.MyView2);
/* 动画组合顺序说明:
after(Animator anim) 解释: play(Animator)放在after(Animator)后面运行
after(long delay) 解释:同上
before(Animator anim) 解释:play(Animator) 放在 before(Animator anim) 前面运行
with(Animator anim) 解释:play(Animator) 与 with(Animator anim) 同时运行
顺序关系:
先 after > (play=with) > before 后
*/
//设置颜色 0x(进制)FF(透明度)38184E(RGB颜色值) 注意!两个颜色跨度不应该过大,否则会闪。
ObjectAnimator objectAnimator1 = ObjectAnimator.ofInt(view2,"backgroundColor",0xFF88FF88,0xFF88FFE7);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(view2,"translationX",500);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(view2,"translationY",800);
ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(view2,"rotation",-90,90);
AnimatorSet animatorSet = new AnimatorSet();
//组合动画
// 先执行 objectAnimator4 旋转
// 在同步运行objectAnimator1变色和objectAnimator2 向右移动
// 然后在运行objectAnimator4向下
animatorSet.play(objectAnimator1).after(objectAnimator4).before(objectAnimator3).with(objectAnimator2);
animatorSet.setDuration(5000);
animatorSet.start();

大量动画的组合方式:

        view2 = (MyView_1)findViewById(R.id.MyView2);
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(view2,"x",980);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(view2,"y",1440);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(view2,"x",0);
ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(view2,"y",0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(objectAnimator1).before(objectAnimator2);
animatorSet.play(objectAnimator2).before(objectAnimator3);
animatorSet.play(objectAnimator3).before(objectAnimator4);
animatorSet.setDuration(5000);
animatorSet.start();

循环播放动画:

         view2 = (MyView_1)findViewById(R.id.MyView2);
float[] f = new float[]{200} ;
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(view2,"translationX",f);
objectAnimator1.setDuration(3000);
//重复次数 备注:这里的次数是从0开始计算的 1 等于2次。 另外如果参数是-1等于无限循环
objectAnimator1.setRepeatCount(1);
//重复模式 ValueAnimator.RESTART 重新开始
objectAnimator1.setRepeatMode(ValueAnimator.RESTART);
objectAnimator1.start();

objectAnimator1.setRepeatMode(ValueAnimator.REVERSE); 另个属性为反向,先按照动画步骤返回在进行重复

最后是其他api的详细解释:

  • setDuration(long duration) 
    通过setDuration方法可以设置动画总共的持续时间,以毫秒为单位。

  • start() 
    通过start方法可以启动动画,动画启动后不一定会立即运行。如果之前通过调用setStartDelay方法设置了动画延迟时间,那么会在经过延迟时间之后再运行动画;如果没有设置过动画的延迟时间,那么动画在调用了start()方法之后会立即运行。在调用了start()方法之后,动画的isStarted()方法就会返回true;在动画真正运行起来之后,动画的isRunning()方法就会返回true,这时候动画才会调用TimeInterpolator才开始工作计算属性在某个时刻的值。调用动画的start()方法所在的线程必须绑定了一个Looper对象,如果没有绑定就会报错。当然,UI线程(即主线程)早就默认绑定了一个Looper对象,所以在主线程中我们就无需担心这个问题。如果我们想在一个View上使用属性动画,那么我们应该保证我们是在UI线程上调用的动画的start()方法。start()方法运行后会触发动画监听器AnimatorListener的onAnimationStart方法的执行。

  • setStartDelay(long startDelay) 
    可以通过调用setStartDelay方法设置动画的延迟运行时间,比如调用setStartDelay(1000)意味着动画在执行了start()方法1秒之后才真正运行,这种情况下,在调用了start()方法之后,isStarted()方法返回true,表示动画已经启动了,但是在start()方法调用后1s内,isRunning()方法返回false,表示动画还未真正运行,比如在start()方法调用后第0.5秒,由于动画还在延迟阶段,所以isRunning()返回false;在start()方法执行1秒之后,isStarted()方法还是返回true,isRunning()方法也返回了true,表示动画已经真正开始运行了。通过调用getStartDelay()方法可以返回我们设置的动画延迟启动时间,默认值是0。

  • setInterpolator(TimeInterpolator value) 
    我们可以通过调用setInterpolator方法改变动画所使用的时间插值器,由于视图动画也需要使用时间插值器,所以我们可以使用android.view.animation命名空间下的一系列插值器,将其与属性动画一起工作。通过动画的getInterpolator方法可以获取我们设置的时间插值器。

  • setTarget(Object target) 
    可以通过调用动画的setTarget方法设置其要操作的对象,这样可以更新该对象的某个属性值。实际上,该方法对于ValueAnimator作用不大,因为ValueAnimator不是直接与某个对象打交道的。setTarget方法对于ObjectAnimator作用较大,因为ObjectAnimator需要绑定某个要操作的对象,下面会详细介绍。

  • pause() 
    Android中API Level 19在Animator中加入了pause()方法,该方法可以暂停动画的执行。调用pause()方法的线程必须与调用start()方法的线程是同一个线程。如果动画还没有执行start()或者动画已经结束了,那么调用pause()方法没有任何影响,直接被忽略。当执行了pause()方法后,动画的isPaused()方法会返回true。pause()方法运行后会触发动画监听器AnimatorPauseListener的onAnimationPause方法的执行。

  • resume() 
    如果动画通过调用pause()方法暂停了,那么之后可以通过调用resume()方法让动画从上次暂停的地方继续运行。resume()方法也是从API Level 19引入的,并且调用resume()方法的线程必须与调用start()方法的线程是同一个线程。如果动画没有处于暂停状态(即isPaused()返回false),那么调用resume()方法会被忽略。resume()方法运行后会触发动画监听器AnimatorPauseListener的onAnimationResume方法的执行。

  • end 
    end()方法执行后,动画会结束运行,直接从当前状态跳转到最终的完成状态,并将属性值分配成动画的终止值,并触发动画监听器AnimatorListener的onAnimationEnd方法的执行。

  • cancel() 
    cancel()方法执行后,动画也会结束运行,但是与调用end方法不同的是,其不会将属性值分配给动画的终止值。比如一个动画在400ms内将对象的x属性从0渐变为40,当运行到第200ms时调用了cancel()方法,那么属性x的最终值是20,而不是40,这是与调用end()方法不同的,如果在第200ms调用了end()方法,那么属性x的最终值是40。调用cancel()方法后,会先触发AnimatorListener的onAnimationCancel方法的执行,然后触发onAnimationEnd方法的执行。

  • clone() 
    Animator实现了Java.lang.Cloneable接口。Animator的clone()方法会对动画进行拷贝,但是该方法默认实现的只是浅拷贝,子类可以重写该方法以实现深拷贝。

  • addListener (Animator.AnimatorListener listener) 
    可以通过addListener方法向Animator添加动画监听器,该方法接收的是AnimatorListener接口类型的参数,其具有四个方法:onAnimationStart、onAnimationCancel、onAnimationEnd、onAnimationRepeat。我们上面已经介绍了前三个方法,onAnimationRepeat方法会在动画在重复播放的时候被回调。Android中的AnimatorListenerAdapter类是个抽象类,其实现了AnimatorListener接口,并为所有方法提供了一个空实现。

  • addPauseListener (Animator.AnimatorPauseListener listener) 
    可以通过addPauseListener方法可以向Animator添加动画暂停相关的监听器,该方法接收的是AnimatorPauseListener接口类型的参数,具有两个方法:onAnimationPause和onAnimationResume,上面已经提到过,在此不再赘述。AnimatorListenerAdapter同样也实现了AnimatorPauseListener接口,并为所有方法提供了一个空实现。

android 开发 View _2_ View的属性动画ObjectAnimator ,动画效果一览的更多相关文章

  1. android开发_view和view属性

    一.view视图的宽度和高度属性,属性值:固定和浮动两种状态 1属性为固定值 <View android:layout_width="30dp" android:layout ...

  2. android开发之自定义View 详解 资料整理 小冰原创整理,原创作品。

    2019独角兽企业重金招聘Python工程师标准>>> /** * 作者:David Zheng on 2015/11/7 15:38 * * 网站:http://www.93sec ...

  3. Android开发进阶——自定义View的使用及其原理探索

    在Android开发中,系统提供给我们的UI控件是有限的,当我们需要使用一些特殊的控件的时候,只靠系统提供的控件,可能无法达到我们想要的效果,这时,就需要我们自定义一些控件,来完成我们想要的效果了.下 ...

  4. Android 自定义View修炼-Android开发之自定义View开发及实例详解

    在开发Android应用的过程中,难免需要自定义View,其实自定义View不难,只要了解原理,实现起来就没有那么难. 其主要原理就是继承View,重写构造方法.onDraw,(onMeasure)等 ...

  5. android开发学习 ------- 自定义View 圆 ,其点击事件 及 确定当前view的层级关系

    我需要实现下面的效果:   参考文章:https://blog.csdn.net/halaoda/article/details/78177069 涉及的View事件分发机制 https://www. ...

  6. 深入Android开发之--理解View#onTouchEvent

    一:前言 View是Android中最基本的UI单元. 当一个View接收到了触碰事件时,会调用其onTouchEvent方法.方法声明如下: ? 1 2 3 4 5 6 7 /**  * Imple ...

  7. Android 开发中的View事件监听机制

    在开发过程中,我们常常根据实际的需要绘制自己的应用组件,那么定制自己的监听事件,及相应的处理方法是必要的.我们都知道Android中,事件的监听是基于回调机制的,比如常用的OnClick事件,你了解它 ...

  8. Android 开发 -------- 自己定义View 画 五子棋

    自己定义View  实现 五子棋 配图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG92ZV9KYXZjX3lvdQ==/font/5a6L5L2T ...

  9. DDMS android 开发工具-----dump View Hierarchy for UI automator

    今天又发现一个好工具  dump View Hierarchy 对学习UI布局非常有优点,操作也非常easy的.直接上图说话了 watermark/2/text/aHR0cDovL2Jsb2cuY3N ...

随机推荐

  1. JAVA 根据设置的概率生成随机数

    import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; i ...

  2. 高性能场景下,HashMap的优化使用建议

    1. HashMap 在JDK 7 与 JDK8 下的差别 顺便理一下HashMap.get(Object key)的几个关键步骤,作为后面讨论的基础. 1.1 获取key的HashCode并二次加工 ...

  3. JavaScript之循环

    我是昨天的小尾巴...https://blog.csdn.net/weixin_42217154/article/details/81182817 3.2 循环结构 循环结构是指在程序中需要反复执行某 ...

  4. 一款非常不错的重写listctrl类-CListCtrlEx

    原文在:https://www.codeproject.com/Articles/28063/An-Extended-MFC-CListCtrl-to-edit-individual-cells li ...

  5. jquery mCustomScrollbar 滚动条宽度的设置

    一.项目使用 $("#iscroll-1, #tree_box, .work, .item1, .item2, .item3, .item4").mCustomScrollbar( ...

  6. 3.oracle与mysql的区别

    1.自动增长的数据类型处理     MYSQL有自动增长的数据类型,插入记录时不用操作此字段,会自动获得数据值.ORACLE没有自动增长的数据类型,需要建立一个自动增长的序列号,插入记录时要把序列号的 ...

  7. 神州数码OSPF Stub(末梢区域)和Totally Stub(完全末梢区域)的配置

    实验要求:了解末梢区域及完全末梢区域的配置 拓扑如下 R1 enable 进入特权模式 config 进入全局模式 hostname R1 修改名称 interface l0 进入端口 ip addr ...

  8. hadoop day 5

    1.Zookeeper Zookeeper的安装和配置(集群模式) 1)在conf目录下创建一个配置文件zoo.cfg, tickTime=2000——心跳检测的时间间隔(ms) dataDir=/U ...

  9. mod_conference ESL控制三(程序)

    第一篇描述了mod_conference控制原理,第二篇描述了conference相关事件,接下来对esl内联程序做简要说明. 由于event-socket采用TCP协议,因此需要一个线程与frees ...

  10. ubuntu 初始安装完成后的一些设置

    处于安全考虑最好,使用普通用户登录. 首先以超级用户登入系统,然后执行以下步骤 第一步:设置普通用户 以下<user_name>代表普通用户的用户名 useradd -g users -d ...