AI智能
改变未来

Android之动画

好看的界面离不开好看、流畅的动画,Android系统提供2大动画系统:传动动画和属性动画。

启动传动动画又分为帧动画和补间动画;

帧动画:即图形以一帧一帧的形式播放的动画,像gif一样的效果;

补间动画:即我们常见的alpha(透明度),translate(位移),scale(缩放)、rotate(旋转)动画。

下面我们开始分别来介绍:

帧动画:

效果如上所示,下面来看看怎么实现的。

首先我们需要新建一个drawable文件 animation :

[code]<?xml version=\"1.0\" encoding=\"utf-8\"?><animation-list xmlns:android=\"http://schemas.android.com/apk/res/android\"><itemandroid:drawable=\"@drawable/an_1\"android:duration=\"100\" /><itemandroid:drawable=\"@drawable/an_2\"android:duration=\"100\" />……总共31张图片 an_1到an_31</animation-list>

然后我们在xml中定义个ImageView并且设置src为刚刚定义的drawable:

[code]<?xml version=\"1.0\" encoding=\"utf-8\"?><LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"xmlns:tools=\"http://schemas.android.com/tools\"android:layout_width=\"match_parent\"android:layout_height=\"match_parent\"android:orientation=\"vertical\"tools:context=\".AActivity\"><ImageViewandroid:id=\"@+id/acMainImgAnimation\"android:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:src=\"@drawable/animation\" /></LinearLayout>

最后只需要在代码中启动动画即可:

[code]val an = acMainImgAnimation.drawable as AnimationDrawablean.start()

先获取图片的drawable,然后转为AnimationDrawable类,看名字就知道它是一个drawable的动画类,然后调用start启动即可。

补间动画:

补间动画的创建分xml和代码创建,我们先来看看xml怎么创建:

现在res目录创建anim目录,然后在此目录下创建动画文件

我们直接来看set.xml,即所有动画的集合,对,没错,上面提到的4种动画是可以同时设置的,任意组合。

[code]<?xml version=\"1.0\" encoding=\"utf-8\"?><set xmlns:android=\"http://schemas.android.com/apk/res/android\"android:duration=\"1000\"android:interpolator=\"@android:anim/accelerate_decelerate_interpolator\"android:repeatCount=\"infinite\"android:repeatMode=\"reverse\"android:shareInterpolator=\"true\"><alphaandroid:duration=\"1000\"android:fromAlpha=\"0\"android:toAlpha=\"1\" /><rotateandroid:duration=\"1000\"android:fromDegrees=\"0\"android:pivotX=\"50%\"android:pivotY=\"50%\"android:repeatCount=\"infinite\"android:repeatMode=\"reverse\"android:startOffset=\"500\"android:toDegrees=\"360\" /><scaleandroid:duration=\"1000\"android:fromXScale=\"0\"android:fromYScale=\"0\"android:pivotX=\"50%\"android:pivotY=\"50%\"android:repeatCount=\"infinite\"android:repeatMode=\"reverse\"android:toXScale=\"1\"android:toYScale=\"1\" /><translateandroid:duration=\"1000\"android:fromXDelta=\"0%\"android:fromYDelta=\"0%\"android:repeatCount=\"infinite\"android:repeatMode=\"reverse\"android:toXDelta=\"200%\"android:toYDelta=\"0%\" /></set>

下面来分别介绍各个标签的意思:

duration:动画持续时间

interpolator:差值器,即动画在执行的时间里按照一定的速率变化。如匀速、加速、减速等等。

repeatCount:正数就是动画执行多少次,infinite无限循环。

repeatMode:重复执行的时候以什么样式reverse:倒叙,如一个从左往右的动画,第二次的时候就是从右往左。restart:重新开始,如从左往右,下一次控件会回到原始位置再从左往右。

shareInterpolator:包含的所有动画是否统一使用一个差值器。

startOffset:开始之前延时多少毫秒

关于坐标:旋转、缩放、位移动画中都会有关于x、y轴位置的设置,如果直接写数字那么就是指定的屏幕坐标,数字后面加%则是相对于自身的坐标,最后面加p则是相对于父控件。如上面最后的translate fromXDelta=“0%” 是指的X轴开始位置是自身的0坐标。

alpha 透明度:

fromAlpha:开始的透明度(0——1)

toAlpha:介绍时的透明度(0——1)

rotate 旋转:

pivotX:X轴的中心点

pivotY:Y轴中心点

fromDegrees:开始的角度

toDegrees:结束角度

scale 缩放:

fromXScale:X轴开始的比例(0——1)

fromYScale:Y轴开始的比例(0——1)

toXScale:X轴结束的比例(0——1)

toYScale:Y轴结束的比例(0——1)

translate 位移:

fromXDelta:X轴开始的位置

fromYDelta:Y轴开始的位置

toXDelta:X轴结束的位置

toYDelta:Y 轴结束的位置

[code]//从xml加载动画val alphaAnimation = AnimationUtils.loadAnimation(this, R.anim.alpha)acMainViewAnAlpha.startAnimation(alphaAnimation)val translateAnimation = AnimationUtils.loadAnimation(this, R.anim.translate)acMainViewAnTranslate.startAnimation(translateAnimation)val scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.scale)acMainViewAnScale.startAnimation(scaleAnimation)val rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.rotate)acMainViewAnRotate.startAnimation(rotateAnimation)val animation = AnimationUtils.loadAnimation(this, R.anim.set)acMainViewAnSet.startAnimation(animation)

下面来看看代码怎么创建:

先新建一个AnimationTools

[code]object AnimationTools {/*** 获取透明度动画*/fun getAlpha(): Animation {//第一个参数为开始透明度,第二个为结束透明度val animation = AlphaAnimation(0f, 1f)animation.duration = 1000animation.repeatMode = Animation.REVERSEanimation.repeatCount = Animation.INFINITEreturn animation}fun getScale(): Animation {/*第一个X开始位置第二个X结束位置第三个Y开始位置第四个Y结束位置第五个缩放的相对位置类型,这里设置的相对空间自身,跟xml里面写%一样第六个为X轴缩放中心点第七第八同理为Y轴*/val animation = ScaleAnimation(0f, 1f, 0f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f)animation.duration = 1000animation.repeatMode = Animation.REVERSEanimation.repeatCount = Animation.INFINITEanimation.interpolator = AccelerateDecelerateInterpolator()return animation}fun getRotate(): Animation {/**第一和第二位开始角度和结束角度* 后面几个参数同上同理*/val animation = RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f)animation.duration = 1000animation.repeatMode = Animation.REVERSEanimation.repeatCount = Animation.INFINITEanimation.interpolator = AccelerateInterpolator(0.9f)return animation}fun getTranslate(): Animation {/*第一个为X轴开始移动相对坐标类型,同上同理为自身或者父控件第二个为X轴开始位置第三第四位X轴结束位置类型和坐标后四个同理为Y轴*/val animation = TranslateAnimation(Animation.RELATIVE_TO_PARENT,0f,Animation.RELATIVE_TO_SELF,2f,Animation.RELATIVE_TO_SELF,0f,Animation.RELATIVE_TO_SELF,0f)animation.duration = 1000animation.repeatMode = Animation.REVERSEanimation.repeatCount = Animation.INFINITEanimation.interpolator = DecelerateInterpolator(0.5f)return animation}fun getSet(): Animation {/*AnimationSet通过add方法添加各种其他动画,动画之间是可以通过startOffset来添加延时错开的*/val animation = AnimationSet(true)animation.addAnimation(getAlpha())animation.addAnimation(getScale())animation.addAnimation(getRotate())animation.addAnimation(getTranslate())return animation}}

效果跟之前的是一样的。

下面我们来看看属性动画:

我们先来看一下用法:

[code]//这里定义一个objectAnimator// 第一个参数是我们需要显示动画的控件//第二个参数是要修改的属性,需要注意的是这个属性必须是控件里面有的属性,并且可以修改的,即View是有setXXX方法的。比如我们介绍的这4种动画,这里修改的是透明度//后面的参数跟我们用xml或者代码创建的就是一样的了val alphaAnimation = ObjectAnimator.ofFloat(acMainViewAnAlpha, \"alpha\", 0f, 1f)//同样设置时间和差值器alphaAnimation.duration = 1000alphaAnimation.interpolator = LinearInterpolator()//这里添加了一个动画更新的监听器alphaAnimation.addListener(object : Animator.AnimatorListener {//动画从新开始override fun onAnimationRepeat(animation: Animator?) {}//动画结束override fun onAnimationEnd(animation: Animator?) {}//动画取消override fun onAnimationCancel(animation: Animator?) {}//动画开始override fun onAnimationStart(animation: Animator?) {}})//这里添加一个动画更新的监听器,通过参数可以获取到当前的值是多少,// 比如刚刚设置透明度是0到1,这里就会实时的更新获取到0到1的小数alphaAnimation.addUpdateListener {Log.d(\"ZLog AActivity\", \"onCreate: ${it.animatedValue}\")}//开始运行alphaAnimation.start()

属性动画的运行模式就是通过不断的设置我们需要修改的属性值,然后重绘View来达到动画的效果。

那么我们就可以非常方便的来设置想要的动画了,很多自定义的控件我们就可以通过它来控制动画。

ObjectAnimator类有很多方法可以使用,它的核心是通过设置的持续时间、差值器、开始、结束的值来持续的产生数字,拿到这些数字之后再来更新View。

来看一下ObjectAnimator的父类:

ValueAnimator这个类就是专门用来负责产生持续的数字的。

[code]val animation = ValueAnimator.ofInt(0, 255)animation.duration = 1000animation.addUpdateListener {Log.d(\"ZLog AActivity\", \"updateListener: ${it.animatedValue}\")}animation.start()

上面这段代码就会在1秒之内持续的参数0到255的整数,通过这种动画的形式获取到数字后我们就可以方便的重写绘制View来达到动画效果了。

[code]class ProgressTestView : View {private val paint = Paint()var progressValue = 0fconstructor(context: Context) : this(context, null)constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0)constructor(context: Context, attributeSet: AttributeSet?, style: Int) : super(context, attributeSet, style) {paint.strokeWidth = 30fpaint.color = Color.REDstartAnimation()}/*** 核心代码,开始动画*/private fun startAnimation() {val animation = ValueAnimator.ofFloat(0f, 1f)animation.duration = 5000animation.interpolator = DecelerateInterpolator(0.8f)animation.repeatCount = ValueAnimator.INFINITEanimation.repeatMode = ValueAnimator.REVERSE//上面都是基本的一些动画设置,在这里添加更新的回调animation.addUpdateListener {//通过回调参数拿到当前值progressValue = it.animatedValue as Float//触发重绘invalidate()}animation.start()}override fun onDraw(canvas: Canvas?) {super.onDraw(canvas)canvas?.let {//这里更近当前进度值绘制一条横线val w = width * progressValueit.drawLine(0f, 20f, w, 20f, paint)}}}

通过上面的代码我们能够进一步的理解ValueAnimator。刚刚的View里面控制进度或者说能进行动画效果的属性是progressValue,那么我们能不能使用之前的ObjectAnimator来处理呢?

首先我们在ProgresTextView里面取消动画的执行

[code]constructor(context: Context, attributeSet: AttributeSet?, style: Int) : super(context, attributeSet, style) {paint.strokeWidth = 30fpaint.color = Color.RED//        startAnimation()}

然后对progressValue属性的设置方法做一下修改:

[code]  var progressValue = 0fset(value) {field = valueinvalidate()}

就是在设置的时候进行重绘。

最后在Activity的代码中加入下面的代码:

[code]    override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val animation = ObjectAnimator.ofFloat(acMainView, \"progressValue\", 0f, 1f)animation.duration = 5000animation.interpolator = DecelerateInterpolator(0.8f)animation.repeatCount = ValueAnimator.INFINITEanimation.repeatMode = ValueAnimator.REVERSEanimation.start()}

这样动画就能跟刚才一样执行了

好了,动画相关的内容就先讲到这里,上面关于自定义View的内容将会在后面分几个部分来介绍。因为它涉及到测量、布局、重绘和点击事件(Android系统点击事件分发机制)这些内容,相对比较复杂,所以会分几个模块来介绍。

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » Android之动画