AndroID开发中,动画特效是经常遇到的,接下来对这块知识点做一下总结。
一.逐帧动画定义逐帧动画逐帧(Frame)动画,就是动画过程的每张静态的图片都收集起来,然后由AndroID来控制依次展示这些静态图片,再利用人眼的“视觉残留”原理,给用户呈现动画的错觉。(逐帧动画的原理和放电影的原理一致)
在< animation-List… />元素中使用< item…/ >子元素定义动画的全部帧即可
<?xml version="1.0" enCoding="utf-8"?><!--添加多个帧--><animation-List xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:oneshot="false"> <item androID:drawable="@drawable/ic_frame0" androID:duration="60"/> <item androID:drawable="@drawable/ic_frame1" androID:duration="60"/> <item androID:drawable="@drawable/ic_frame2" androID:duration="60"/> <item androID:drawable="@drawable/ic_frame3" androID:duration="60"/> <!--下面忽略多个item--></animation-List>
使用逐帧动画上面的xml文件定义了一个逐帧动画资源,androID:oneshot为false指的可以循环播放动画
class MainAnimActivity : AppCompatActivity() { overrIDe fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentVIEw(R.layout.activity_main_anim) val framImageVIEw = findVIEwByID<ImageVIEw>(R.ID.fram_imge) val playAniBtn = findVIEwByID<button>(R.ID.play_btn) val stopAniBtn = findVIEwByID<button>(R.ID.stop_btn) val anim = framImageVIEw.background playAniBtn.setonClickListener{v -> if (anim is AnimationDrawable) { anim.start() } } stopAniBtn.setonClickListener {v -> if (anim is AnimationDrawable) { anim.stop() } } }}
代码创建逐帧动画AnimationDrawble(An object used to create frame-by-frame animations)代表的动画默认不播放,提供如下方法来开始、结束动画
start() 开始播放动画
end() 结束动画
val animationDrawable = AnimationDrawable() animationDrawable.addFrame(resources.getDrawable(R.drawable.ic_frame0), 60) animationDrawable.addFrame(resources.getDrawable(R.drawable.ic_frame1), 60) animationDrawable.addFrame(resources.getDrawable(R.drawable.ic_frame2), 60) animationDrawable.addFrame(resources.getDrawable(R.drawable.ic_frame3), 60) animationDrawable.isOneshot = false framImageVIEw.background = animationDrawable playAniBtn.setonClickListener{v -> animationDrawable.start() } stopAniBtn.setonClickListener {v -> animationDrawable.stop() }
二.补间动画补间动画,就是指开发者只需指定动画开始、动画结束等“关键帧”,而动画变化的“中间帧”由系统计算并补齐。
AndroID使用Animation代表抽象的动画类
包含如下几个子类:AlphaAnimation(透明度动画)、ScaleAnimation(缩放动画)、TranslateAnimation(位移动画)、RotationAnimation(旋转动画)
使用补间动画AnimationSet : 组合多个补间动画时使用
res/anim/tween_anim.xml
<?xml version="1.0" enCoding="utf-8"?><set xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:interpolator="@androID:anim/linear_interpolator"> <!--缩放 --> <scale androID:duration="3000" androID:fillAfter="true" androID:fromXScale="1.0" androID:fromYScale="1.0" androID:pivotX="50%" androID:pivotY="50%" androID:toXScale="0.1" androID:toYScale="0.1" /> <!--透明度--> <Alpha androID:duration="3000" androID:fromAlpha="1" androID:toAlpha="0.05" /> <!-- 旋转 --> <rotate androID:duration="3000" androID:fromdegrees="0" androID:pivotX="50%" androID:pivotY="50%" androID:todegrees="180" /> <!--平移--> <translate androID:duration="3000" androID:fromXDelta="100" androID:fromYDelta="100" androID:toXDelta="200" androID:toYDelta="100" /></set>
//通过AnimationUtils得到代表动画的Animation之后,就可以调用vIEw的startAnimation(Animation anim)方法开始对该vIEw执行动画了val loadAnimation = AnimationUtils.loadAnimation(this, R.anim.tween_anim) playAniBtn.setonClickListener{v -> framImageVIEw.startAnimation(loadAnimation) }
代码创建补间动画//透明度动画val AlphaAnimation = AlphaAnimation(1f, 0f)AlphaAnimation.duration = 3000//旋转动画/** 创建一个旋转动画对象* 入参列表含义如下:* 1.fromdegrees:从哪个角度开始旋转* 2.todegrees:旋转到哪个角度结束* 3.pivotXType:旋转所围绕的圆心的x轴坐标的类型,有ABSolUT绝对坐标、relative_TO_SELF相对于自身坐标、relative_TO_PARENT相对于父控件的坐标* 4.pivotXValue:旋转所围绕的圆心的x轴坐标,0.5f表明是以自身这个控件的一半长度为x轴* 5.pivotYType:y轴坐标的类型* 6.pivotYValue:y轴坐标*/val rotateAnimation = RotateAnimation(0f, 360f, Animation.relative_TO_SELF, 0.5f, Animation.relative_TO_SELF, 0.5f);rotateAnimation.duration = 3000//缩放动画/** 创建一个缩放效果的动画* 入参列表含义如下:* fromX:x轴的初始值* toX:x轴缩放后的值* fromY:y轴的初始值* toY:y轴缩放后的值* pivotXType:x轴坐标的类型,有ABSolUT绝对坐标、relative_TO_SELF相对于自身坐标、relative_TO_PARENT相对于父控件的坐标* pivotXValue:x轴的值,0.5f表明是以自身这个控件的一半长度为x轴* pivotYType:y轴坐标的类型* pivotYValue:轴的值,0.5f表明是以自身这个控件的一半长度为y轴*/val scaleAnimation = ScaleAnimation(1f, 0.8f, 1f, 0.8f, Animation.relative_TO_SELF, 0.5f, Animation.relative_TO_SELF, 0.5f)scaleAnimation.duration = 3000//平移动画/* * 创建一个移动动画效果 * 入参的含义如下: * fromXType:移动前的x轴坐标的类型 * fromXValue:移动前的x轴的坐标 * toXType:移动后的x轴的坐标的类型 * toXValue:移动后的x轴的坐标 * fromYType:移动前的y轴的坐标的类型 * fromYValue:移动前的y轴的坐标 * toYType:移动后的y轴的坐标的类型 * toYValue:移动后的y轴的坐标 */val translateAnimation = TranslateAnimation(Animation.relative_TO_SELF, 0f, Animation.relative_TO_SELF, 0.2f, Animation.relative_TO_SELF, 0f, Animation.relative_TO_SELF, 0.2f)translateAnimation.duration = 3000playAniBtn.setonClickListener { v -> val animationSet = AnimationSet(true) animationSet.addAnimation(AlphaAnimation) animationSet.addAnimation(rotateAnimation) animationSet.addAnimation(scaleAnimation) animationSet.addAnimation(translateAnimation) //播放组合补间动画 framImageVIEw.startAnimation(animationSet) //播放单一补间动画 //framImageVIEw.startAnimation(AlphaAnimation)}
补间动画只是去改变vIEw的展示效果,不会真正改变vIEw的属性 val translateAnimation = TranslateAnimation(Animation.relative_TO_SELF, 0f, Animation.relative_TO_SELF, 1.5f, Animation.relative_TO_SELF, 0f, Animation.relative_TO_SELF, 0f) translateAnimation.fillAfter = true //延迟2秒执行平移动画 //对比平移前点击按钮和平移后点击按钮的现象 mHandler.postDelayed(Runnable { mTransBtn?.startAnimation(translateAnimation) }, 2000) mTransBtn?.setonClickListener { Toast.makeText(this@MainActivity, getString(R.string.click_trans_btn), Toast.LENGTH_SHORT).show() }
平移后的按钮无法触发我们注册的点击事件,而此时平移前按钮的位置是可以触发该点击事件的,因为实际上这个按钮还是停留在平移前的位置,只不过补间动画将这个按钮绘制到了平移后的位置
三.属性动画注:属性动画对vIEw属性进行动画,解决了该问题
属性动画,可以定义任何属性的变化,从某种角度来看,属性动画是增强版的补间动画
1.补间动画只能定义在透明度、旋转、缩放、位移,这4个方面的变化,但属性动画可以定义任何属性的变化
2.补间动画只能对ui组件执行动画,但属性动画几乎可以对任何对象执行动画(不管是否显示在屏幕上)
Animator 提供了创建属性动画的基类,基本不会直接使用该类,通常只用于被继承并重写它的相关方法
使用ObjectAnimator属性动画ValueAnimator:主要负责计算各帧的属性值,更新对象的相关属性值时使用
ObjectAnimator:是ValueAnimator的子类,对指定对象的属性执行动画时使用
AnimatorSet:组合多个属性动画时使用
//透明度属性动画 mAlphaAnimator = ObjectAnimator.offloat(mMylove, "Alpha", 0.2f, 1f) //mAlphaAnimator?.start() //使用Alpha属性动画 //缩放属性动画 mScaleAnimatorX = ObjectAnimator.offloat(mMylove, "scaleX", 1f, 1.1f) mScaleAnimatorY = ObjectAnimator.offloat(mMylove, "scaleY", 1f, 1.1f) //组合属性动画 mAnimatorSet = AnimatorSet() mAnimatorSet?.duration = 3000 mAnimatorSet?.playTogether(mScaleAnimatorX, mScaleAnimatorY, mAlphaAnimator) mAnimatorSet?.start() //使用组合属性动画
使用ValueAnimator属性动画 //ValueAnimator属性动画 mProgressAnimator = ValueAnimator.ofInt(0, 100) mProgressAnimator?.setDuration(3000) mProgressAnimator?.addUpdateListener(AnimatorUpdateListener { animation -> Log.i(TAG, "onAnimationUpdate :: " + animation.animatedValue) mProgressbar?.progress = (animation.animatedValue as Int) }) mProgressAnimator?.addListener(object : Animator.AnimatorListener { overrIDe fun onAnimationStart(animation: Animator) { Toast.makeText(this@MainActivity, "动画开始", Toast.LENGTH_SHORT).show() } overrIDe fun onAnimationEnd(animation: Animator) { Toast.makeText(this@MainActivity, "动画结束", Toast.LENGTH_SHORT).show() } overrIDe fun onAnimationCancel(animation: Animator) { Toast.makeText(this@MainActivity, "动画取消", Toast.LENGTH_SHORT).show() } overrIDe fun onAnimationRepeat(animation: Animator) { Toast.makeText(this@MainActivity, "动画重复", Toast.LENGTH_SHORT).show() } }) //色值ValueAnimator属性动画 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LolliPOP) { mcolorAnimator = ValueAnimator.ofArgb(-0x1, -0x10000, -0xffff01, -0xff0100) } mcolorAnimator?.duration = 3000 mcolorAnimator?.addUpdateListener { animation -> mStartBtn?.setBackgroundcolor((animation.animatedValue as Int)) }
xml文件定义属性动画res/animator/animator_set.xml
<?xml version="1.0" enCoding="utf-8"?><set xmlns:androID="http://schemas.androID.com/apk/res/androID"> <objectAnimator androID:duration="3000" androID:propertyname="Alpha" androID:valueFrom="0.2" androID:valueto="1.0" androID:valueType="floatType"> </objectAnimator> <objectAnimator androID:duration="3000" androID:propertyname="scaleX" androID:valueFrom="1.0" androID:valueto="1.1" androID:valueType="floatType"> </objectAnimator> <objectAnimator androID:duration="3000" androID:propertyname="scaleY" androID:valueFrom="1.0" androID:valueto="1.1" androID:valueType="floatType"> </objectAnimator></set>
res/animator/animator_Alpha.xml
<?xml version="1.0" enCoding="utf-8"?><objectAnimator xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:duration="3000" androID:propertyname="Alpha" androID:valueFrom="0.2" androID:valueto="1.0" androID:valueType="floatType"></objectAnimator>
代码中使用在xml中定义的属性动画
//加载xml中属性动画 val animatorset = AnimatorInflater.loadAnimator(this, R.animator.animator_set) as AnimatorSet val animator = AnimatorInflater.loadAnimator(this, R.animator.animator_Alpha) //使用组合属性动画 animatorset.setTarget(mMylove) animatorset.start() //使用属性动画 animator.setTarget(mMylove) animator.start()
在使用过程中,可以选择合适的动画进行动画效果实现
传送门:https://github.com/xiaoai-summer/myKotlinDemo
总结以上是内存溢出为你收集整理的Android 动画总结全部内容,希望文章能够帮你解决Android 动画总结所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)