转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/118709616
本文出自【赵彦军的博客】
//透明度
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();
//旋转
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
animator.setDuration(5000);
animator.start();
//x方向偏移
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX", 0, -500f);
animator.setDuration(5000);
animator.start();
//y方向偏移
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationY", 0, -500f);
animator.setDuration(5000);
animator.start();
//x方向缩放
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "scaleX", 1f, 3f, 1f);
animator.setDuration(5000);
animator.start();
//y方向缩放
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "scaleY", 1f, 3f, 1f);
animator.setDuration(5000);
animator.start();
public final class ObjectAnimator extends ValueAnimator {
...
}
ObjectAnimator
继承 ValueAnimator
, 所以 ObjectAnimator
拥有 ValueAnimator
一切特性。
相比于ValueAnimator
,ObjectAnimator
可能才是我们最常接触到的类,因为ValueAnimator
只不过是对值进行了一个平滑的动画过渡,但我们实际使用到这种功能的场景好像并不多。而ObjectAnimator
则就不同了,它是可以直接对任意对象的任意属性进行动画操作的,比如说View
的alpha
属性。
不过虽说ObjectAnimator
会更加常用一些,但是它其实是继承自ValueAnimator
的,底层的动画实现机制也是基于ValueAnimator来完成的,因此ValueAnimator
仍然是整个属性动画当中最核心的一个类。那么既然是继承关系,说明ValueAnimator
中可以使用的方法在ObjectAnimator
中也是可以正常使用的,它们的用法也非常类似,这里如果我们想要将一个TextView
在5秒中内从常规变换成全透明,再从全透明变换成常规,就可以这样写:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();
可以看到,我们还是调用了ofFloat()
方法来去创建一个ObjectAnimator
的实例,只不过ofFloat()
方法当中接收的参数有点变化了。这里第一个参数要求传入一个object
对象,我们想要对哪个对象进行动画操作就传入什么,这里我传入了一个textview
。第二个参数是想要对该对象的哪个属性进行动画操作,由于我们想要改变TextView
的不透明度,因此这里传入"alpha"
。后面的参数就是不固定长度了,想要完成什么样的动画就传入什么值,这里传入的值就表示将TextView
从常规变换成全透明,再从全透明变换成常规。之后调用setDuration()
方法来设置动画的时长,然后调用start()
方法启动动画,效果如下图所示:
学会了这一个用法之后,其它的用法我们就可以举一反三了,那比如说我们想要将TextView
进行一次360度
的旋转,就可以这样写:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
animator.setDuration(5000);
animator.start();
可以看到,这里我们将第二个参数改成了"rotation"
,然后将动画的初始值和结束值分别设置成0和360
,现在运行一下代码,效果如下图所示:
那么如果想要将TextView先向左移出屏幕,然后再移动回来,就可以这样写:
float curTranslationX = textview.getTranslationX();
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX", curTranslationX, -500f, curTranslationX);
animator.setDuration(5000);
animator.start();
这里我们先是调用了TextView
的getTranslationX()
方法来获取到当前TextView的translationX
的位置,然后ofFloat()
方法的第二个参数传入"translationX"
,紧接着后面三个参数用于告诉系统TextView
应该怎么移动,现在运行一下代码,效果如下图所示:
然后我们还可以TextView
进行缩放操作,比如说将TextView
在垂直方向上放大3倍再还原,就可以这样写:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "scaleY", 1f, 3f, 1f);
animator.setDuration(5000);
animator.start();
这里将ofFloat()方法的第二个参数改成了"scaleY",表示在垂直方向上进行缩放,现在重新运行一下程序,效果如下图所示:
到目前为止,ObjectAnimator
的用法还算是相当简单吧,但是我相信肯定会有不少朋友现在心里都有同样一个疑问,就是ofFloat()
方法的第二个参数到底可以传哪些值呢?
目前我们使用过了alpha
、rotation
、translationX
和scaleY
这几个值,分别可以完成淡入淡出、旋转、水平移动、垂直缩放这几种动画,那么还有哪些值是可以使用的呢?
其实这个问题的答案非常玄乎,就是我们可以传入任意的值到ofFloat()
方法的第二个参数当中。任意的值?相信这很出乎大家的意料吧,但事实就是如此。因为ObjectAnimator
在设计的时候就没有针对于View
来进行设计,而是针对于任意对象的,它所负责的工作就是不断地向某个对象中的某个属性进行赋值,然后对象根据属性值的改变再来决定如何展现出来。
那么比如说我们调用下面这样一段代码:
ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f);
其实这段代码的意思就是ObjectAnimator
会帮我们不断地改变textview
对象中alpha
属性的值,从1f变化到0f。然后textview
对象需要根据alpha
属性值的改变来不断刷新界面的显示,从而让用户可以看出淡入淡出的动画效果。
那么textview
对象中是不是有alpha
属性这个值呢?
没有,不仅textview
没有这个属性,连它所有的父类也是没有这个属性的!
这就奇怪了,textview
当中并没有alpha这个属性,ObjectAnimator
是如何进行操作的呢?其实ObjectAnimator
内部的工作机制并不是直接对我们传入的属性名进行操作的,而是会去寻找这个属性名对应的get和set
方法,因此alpha属性所对应的get和set
方法应该就是:
public void setAlpha(float value);
public float getAlpha();
那么textview
对象中是否有这两个方法呢?确实有,并且这两个方法是由View
对象提供的,也就是说不仅TextView
可以使用这个属性来进行淡入淡出动画操作,任何继承自View
的对象都可以的。
既然alpha
是这个样子,相信大家一定已经明白了,前面我们所用的所有属性都是这个工作原理,那么View当中一定也存在着setRotation()
、getRotation()
、setTranslationX()
、getTranslationX()
、setScaleY()
、getScaleY()
这些方法,不信的话你可以到View当中去找一下。
先上效果图:
/**
* @author : zhaoyanjun
* @time : 2021/7/13
* @desc :
*/
class MyView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
private var radius = 10f //圆的半径
set(value) {
field = value
invalidate()
}
private val paint = Paint()
init {
paint.color = Color.BLUE
paint.textSize = 8f
paint.isAntiAlias = true
paint.style = Paint.Style.FILL
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
//绘制圆
canvas?.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), radius, paint)
}
}
有一点很重要的是,radius
的 set 方法中需要调用 invalidate()
方法,才能够刷新view
我们再看执行动画的部分
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var myView: MyView = findViewById(R.id.myView)
//通过动画,不断的改变 radius 的值
var objectAnimator =
ObjectAnimator.ofFloat(myView, "radius", 200f, 500f, 200f)
objectAnimator.duration = 600
objectAnimator.interpolator = LinearInterpolator()
objectAnimator.repeatCount = 20 //执行20次
objectAnimator.start()
}
}