皮皮网

皮皮网

【国外 相机 源码】【rpcx系统源码】【源码审查机构】animation源码

时间:2024-12-25 15:34:38 分类:探索

1.android之animator 和animation 的区别
2.如何在XML中使用自定义Animation动画类
3.UE4AnimNotify 相关源码分析
4.animation和animator的区别

animation源码

android之animator 和animation 的区别

       ä¸€ã€ 前言

       Animator框架是Android 4.0中新添加的一个动画框架,和之前的Animation框架相比,Animator可以进行更多和更精细化的动画控制,而且比之前更简单和更高效。在4.0源码中随处都可以看到Animator的使用。

       äºŒã€ Animation和Animator比较

       å¦‚下图,是Animation和Animator两个类继承图的对比。

       C:Object C:Object

        C:Animation C:Animator

        C:AlphaAnimation C:AnimatorSet

        C:AnimationSet C:ValueAnimator

        C:DummyAnimation C:ObjectAnimator

        C:Rotate3dAnimation C:TimeAnbimator

        C:RotateAniamtion

        C:ScaleAnimation

        C:TranslateAnimation

       Animation框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是一个整个View动画,实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧,如果动画没有完成,继续调用invalidate()函数,启动下次绘制来驱动动画,动画过程中的帧之间间隙时间是绘制函数所消耗的时间,可能会导致动画消耗比较多的CPU资源。

       åœ¨Animator框架中使用最多的是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator进行更精细化控制,只控制一个对象的一个属性值,多个ObjectAnimator组合到AnimatorSet形成一个动画。而且ObjectAnimator能够自动驱动,可以调用setFrameDelay(longframeDelay)设置动画帧之间的间隙时间,调整帧率,减少动画过程中频繁绘制界面,而在不影响动画效果的前提下减少CPU资源消耗。

       ä¸‰ã€ 关键接口介绍

       1. ObjectAnimator介绍

       Animator框架封装得比较完美,对外提供的接口非常简单,创建一个ObjectAnimator只需通过如下图所示的静态工厂类直接返回一个ObjectAnimator对象。传的参数包括一个对象和对象的属性名字,但这个属性必须有get和set函数,内部会通过java反射机制来调用set函数修改对象属性值。还包括属性的初始值,最终值,还可以调用setInterpolator设置曲线函数。

       2. AnimatorSet介绍

       AnimatorSet主要是组合多个AnimatorSet和ObjectAnimator形成一个动画,并可以控制动画的播放顺序,其中还有个辅助类通过调用play函数获得。

       3. AnimatorUpdateListner介绍

       é€šè¿‡å®žçŽ°AnimatorUpdateListner,来获得属性值发生变化时的事件,在这个回调中发起重绘屏幕事件。

       å››ã€ 使用实例

       åœ¨Android4.0中的ApiDemo中有个BouncingBalls实例,描述了Animator框架的使用,当点击屏幕时,绘制一个球从点击位置掉到屏幕底部,碰到底部时球有压扁的效果,然后回弹到点击位置再消失。

       ä»£ç å¦‚下:

       ShapeHolder newBall =addBall(event.getX(), event.getY());

        // Bouncing animation with squash and stretch

        float startY = newBall.getY();

        float endY = getHeight() - f;

        float h = (float)getHeight();

        float eventY = event.getY();

        int duration = (int)( * ((h - eventY)/h));

        ValueAnimator bounceAnim = ObjectAnimator.ofFloat(newBall, "y", startY, endY);

        bounceAnim.setDuration(duration);

        bounceAnim.setInterpolator(new AccelerateInterpolator());

        ValueAnimator squashAnim1 = ObjectAnimator.ofFloat(newBall, "x", newBall.getX(),

        newBall.getX() - f);

        squashAnim1.setDuration(duration/4);

        squashAnim1.setRepeatCount(1);

        squashAnim1.setRepeatMode(ValueAnimator.REVERSE);

        squashAnim1.setInterpolator(new DecelerateInterpolator());

        ValueAnimator squashAnim2 = ObjectAnimator.ofFloat(newBall, "width", newBall.getWidth(),

        newBall.getWidth() + );

        squashAnim2.setDuration(duration/4);

        squashAnim2.setRepeatCount(1);

        squashAnim2.setRepeatMode(ValueAnimator.REVERSE);

        squashAnim2.setInterpolator(new DecelerateInterpolator());

        ValueAnimator stretchAnim1 = ObjectAnimator.ofFloat(newBall, "y", endY,

        endY + f);

        stretchAnim1.setDuration(duration/4);

        stretchAnim1.setRepeatCount(1);

        stretchAnim1.setInterpolator(new DecelerateInterpolator());

        stretchAnim1.setRepeatMode(ValueAnimator.REVERSE);

        ValueAnimator stretchAnim2 = ObjectAnimator.ofFloat(newBall, "height",

        newBall.getHeight(),newBall.getHeight() - );

        stretchAnim2.setDuration(duration/4);

        stretchAnim2.setRepeatCount(1);

        stretchAnim2.setInterpolator(new DecelerateInterpolator());

        stretchAnim2.setRepeatMode(ValueAnimator.REVERSE);

        ValueAnimator bounceBackAnim = ObjectAnimator.ofFloat(newBall, "y", endY,

        startY);

        bounceBackAnim.setDuration(duration);

        bounceBackAnim.setInterpolator(newDecelerateInterpolator());

        // Sequence the down/squash&stretch/upanimations

        AnimatorSet bouncer = new AnimatorSet();

        bouncer.play(bounceAnim).before(squashAnim1);

        bouncer.play(squashAnim1).with(squashAnim2);

        bouncer.play(squashAnim1).with(stretchAnim1);

        bouncer.play(squashAnim1).with(stretchAnim2);

        bouncer.play(bounceBackAnim).after(stretchAnim2);

        // Fading animation - remove the ball when theanimation is done

        ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);

        fadeAnim.setDuration();

        fadeAnim.addListener(new AnimatorListenerAdapter() {

        @Override

        public void onAnimationEnd(Animatoranimation) {

        balls.remove(((ObjectAnimator)animation).getTarget());

        }

        });

        // Sequence the two animations to play oneafter the other

        AnimatorSet animatorSet = new AnimatorSet();

        animatorSet.play(bouncer).before(fadeAnim);

        // Start the animation

        animatorSet.start();

如何在XML中使用自定义Animation动画类

       åœ¨å®‰å“应用的动画开发中,可能SDK中自带的补间动画不能满足应用的需求,需要在Java代码中自定义一些动画类,当然都是继承自Animation类。实现之后,我们一般直接在代码中使用,类似下面这样:CustomAnimationcustomAnimation=newCustomAnimation();customAnimation.setDuration();customAnimation.setFillAfter(true);effectView.startAnimation(customAnimation);当View同时要应用像Scale,Alpha这样的补间动画时,你就需要多添加类似下面的代码:CustomAnimationcustomAnimation=newCustomAnimation();customAnimation.setDuration();customAnimation.setFillAfter(true);AnimationscaleAnimation=newScaleAnimation(0f,1f,0f,1f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);AnimationalphaAnimation=newAlphaAnimation(0.1f,1.0f);scaleAnimation.setDuration();alphaAnimation.setDuration();AnimationSetset=newAnimationSet(true);set.addAnimation(customAnimation);set.addAnimation(scaleAnimation);set.addAnimation(alphaAnimation);set.setFillAfter(true);set.setFillEnabled(true);effectView.startAnimation(set);如果直接在xml中把所需的所有补间动画,包括自定义动画类放到一个集合,事情看起来就没那么复杂。在xml定义好动画集有两个好处:使用动画时需要更少的Java代码,整体上看上去更干净在xml中定义,各个动画属性一目了然也更集中,方便阅读与维护既然有这样的好处,我们就开始干吧。首先在xml中像下面这样定义一个动画集:R.anim.my_anim_setmyapp:customProp2=""myapp:customProp3="%"android:duration=""android:fillAfter="true"/>然后,我们按照常理来,在Java代码中这样来加载我们定义的xml动画集:AnimationSetset=(AnimationSet)AnimationUtils.loadAnimation(this,R.anim.my_anim_set);effectView.startAnimation(set);但是,抱歉!上面的代码是不正确执行,运行起来程序会直接终止。那什么原因呢?查看AnimationUtils.loadAnimation源代码我们知道,在其从xml载入动画类的时候,只认alpha、scale、rotate、translate这几个SDK自带的动画类,而我们写入的自定义动画类CustomAnimation会导致其报Unknownanimationname的异常。官方SDK也没有提供解决这个问题的其他API方法,那么怎么解决呢?很简单,只需在原有的AnimationUtils.loadAnimation源码上改动一行,从ClassLoader载入自定义动画类即可。将其源码拷贝过来,实现一个自己的loadAnimation方法,如下:OptAnimationLoader.javapublicclassOptAnimationLoader{ publicstaticAnimationloadAnimation(Contextcontext,intid)throwsResources.NotFoundException{ XmlResourceParserparser=null;try{ parser=context.getResources().getAnimation(id);returncreateAnimationFromXml(context,parser);}catch(XmlPullParserExceptionex){ Resources.NotFoundExceptionrnf=newResources.NotFoundException("Can'tloadanimationresourceID#0x"+Integer.toHexString(id));rnf.initCause(ex);throwrnf;}catch(IOExceptionex){ Resources.NotFoundExceptionrnf=newResources.NotFoundException("Can'tloadanimationresourceID#0x"+Integer.toHexString(id));rnf.initCause(ex);throwrnf;}finally{ if(parser!=null)parser.close();}}privatestaticAnimationcreateAnimationFromXml(Contextc,XmlPullParserparser)throwsXmlPullParserException,IOException{ returncreateAnimationFromXml(c,parser,null,Xml.asAttributeSet(parser));}privatestaticAnimationcreateAnimationFromXml(Contextc,XmlPullParserparser,AnimationSetparent,AttributeSetattrs)throwsXmlPullParserException,IOException{ Animationanim=null;//Makesureweareonastarttag.inttype;intdepth=parser.getDepth();while(((type=parser.next())!=XmlPullParser.END_TAG||parser.getDepth()>depth)&&type!=XmlPullParser.END_DOCUMENT){ if(type!=XmlPullParser.START_TAG){ continue;}Stringname=parser.getName();if(name.equals("set")){ anim=newAnimationSet(c,attrs);createAnimationFromXml(c,parser,(AnimationSet)anim,attrs);}elseif(name.equals("alpha")){ anim=newAlphaAnimation(c,attrs);}elseif(name.equals("scale")){ anim=newScaleAnimation(c,attrs);}elseif(name.equals("rotate")){ anim=newRotateAnimation(c,attrs);}elseif(name.equals("translate")){ anim=newTranslateAnimation(c,attrs);}else{ try{ anim=(Animation)Class.forName(name).getConstructor(Context.class,AttributeSet.class).newInstance(c,attrs);}catch(Exceptionte){ thrownewRuntimeException("Unknownanimationname:"+parser.getName()+"error:"+te.getMessage());}}if(parent!=null){ parent.addAnimation(anim);}}returnanim;}}这样,使用OptAnimationLoader.loadAnimation方法就可以从xml中载入包含自定义动画的动画集了。

UE4AnimNotify 相关源码分析

       深入解析UE4的动画通知机制:揭秘AnimNotify与AnimNotifyState的协作舞蹈

动画通知的起舞序列</

       在UE4的动画世界里,每帧的Tick函数是核心舞者。首先,AnimNotify</优雅地起舞,国外 相机 源码接着是Tick Pose的轻盈转身,然后是骨矩阵的更新与FinalizeBoneTransform的深情凝视,这是处理Notify/Event Handling的关键环节。而在ConditionallyDispatchQueuedAnimEvents中,AnimNotify和Montage的结束篇章被巧妙触发。

Tick的华丽编舞</

       Tick的步骤如下:AnimNotify</(即启)→ Tick Pose(轻盈步伐)→ 更新骨矩阵(RefreshBoneTransforms)→ FinalizeBoneTransform(情感升华)→ 释放AnimNotifyEvent的绚丽尾声。

通知处理的rpcx系统源码细微转折</

       在UAnimInstance::TriggerAnimNotifies的舞台上,每个新加入的动画通知(AnimNotifyState)都会被逐一审视,可能延后'NotifyBegin'的时机。同时,旧的AnimNotifyState会在触发'NotifyEnd'后优雅谢幕。新状态的源码审查机构'NotifyBegin'随之登场,而'NotifyTick'则在活跃状态下悄然进行。重要的是,尽管'NotifyEnd'总在'NotifyBegin'之前,但可能因帧率变化而稍显滞后。

意外的模拟种植源码节奏混乱</

       帧率的波动可能导致微妙的混乱,例如,当从帧到帧,'NotifyEnd'可能会延迟到下一帧才奏响,尽管时间跨度看似短暂。比如,html漩涡源码当检测到Projectile_0消失时,尽管它在第六帧才真正结束,但'NotifyEnd'却可能在第五帧后才触发,使得动画逻辑出现短暂的不协调。

状态转换的精准切换</

       以SpawnProjectile_0和SpawnProjectile_1为例,Begin阶段的切换精准有序:新状态在检测到新出现的Projectile_1时启动,而当旧状态的Projectile_0消失时,'NotifyEnd'才宣告其结束。从2到2.5帧的过渡,动画队列如丝般流畅地从SpawnProjectile_0切换到SpawnProjectile_1,确保了逻辑的连贯性。

探索更深层次的机制</

       要深入了解动画通知的奥秘,记得查阅官方文档Animation Notifications (Notifies),如果你是一位热衷于开发的舞者,不妨通过邮件gaoyuan.bob@bytedance.com或投递简历链接,加入我们的舞蹈团队,共同探索更精彩的动画世界。

       

animation和animator的区别

       ä¸€ã€ 前言

       Animator框架是Android 4.0中新添加的一个动画框架,和之前的Animation框架相比,Animator可以进行更多和更精细化的动画控制,而且比之前更简单和更高效。在4.0源码中随处都可以看到Animator的使用。

       äºŒã€ Animation和Animator比较

       å¦‚下图,是Animation和Animator两个类继承图的对比。

       C:Object C:Object

        C:Animation C:Animator

        C:AlphaAnimation C:AnimatorSet

        C:AnimationSet C:ValueAnimator

        C:DummyAnimation C:ObjectAnimator

        C:Rotate3dAnimation C:TimeAnbimator

        C:RotateAniamtion

        C:ScaleAnimation

        C:TranslateAnimation

       Animation框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是一个整个View动画,实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧,如果动画没有完成,继续调用invalidate()函数,启动下次绘制来驱动动画,动画过程中的帧之间间隙时间是绘制函数所消耗的时间,可能会导致动画消耗比较多的CPU资源。

       åœ¨Animator框架中使用最多的是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator进行更精细化控制,只控制一个对象的一个属性值,多个ObjectAnimator组合到AnimatorSet形成一个动画。而且ObjectAnimator能够自动驱动,可以调用setFrameDelay(longframeDelay)设置动画帧之间的间隙时间,调整帧率,减少动画过程中频繁绘制界面,而在不影响动画效果的前提下减少CPU资源消耗。

       ä¸‰ã€ 关键接口介绍

       1. ObjectAnimator介绍

       Animator框架封装得比较完美,对外提供的接口非常简单,创建一个ObjectAnimator只需通过如下图所示的静态工厂类直接返回一个ObjectAnimator对象。传的参数包括一个对象和对象的属性名字,但这个属性必须有get和set函数,内部会通过java反射机制来调用set函数修改对象属性值。还包括属性的初始值,最终值,还可以调用setInterpolator设置曲线函数。

       2. AnimatorSet介绍

       AnimatorSet主要是组合多个AnimatorSet和ObjectAnimator形成一个动画,并可以控制动画的播放顺序,其中还有个辅助类通过调用play函数获得。

       3. AnimatorUpdateListner介绍

       é€šè¿‡å®žçŽ°AnimatorUpdateListner,来获得属性值发生变化时的事件,在这个回调中发起重绘屏幕事件。

       å››ã€ 使用实例

       åœ¨Android4.0中的ApiDemo中有个BouncingBalls实例,描述了Animator框架的使用,当点击屏幕时,绘制一个球从点击位置掉到屏幕底部,碰到底部时球有压扁的效果,然后回弹到点击位置再消失。

       ä»£ç å¦‚下:

       ShapeHolder newBall =addBall(event.getX(), event.getY());

        // Bouncing animation with squash and stretch

        float startY = newBall.getY();

        float endY = getHeight() - f;

        float h = (float)getHeight();

        float eventY = event.getY();

        int duration = (int)( * ((h - eventY)/h));

        ValueAnimator bounceAnim = ObjectAnimator.ofFloat(newBall, "y", startY, endY);

        bounceAnim.setDuration(duration);

        bounceAnim.setInterpolator(new AccelerateInterpolator());

        ValueAnimator squashAnim1 = ObjectAnimator.ofFloat(newBall, "x", newBall.getX(),

        newBall.getX() - f);

        squashAnim1.setDuration(duration/4);

        squashAnim1.setRepeatCount(1);

        squashAnim1.setRepeatMode(ValueAnimator.REVERSE);

        squashAnim1.setInterpolator(new DecelerateInterpolator());

        ValueAnimator squashAnim2 = ObjectAnimator.ofFloat(newBall, "width", newBall.getWidth(),

        newBall.getWidth() + );

        squashAnim2.setDuration(duration/4);

        squashAnim2.setRepeatCount(1);

        squashAnim2.setRepeatMode(ValueAnimator.REVERSE);

        squashAnim2.setInterpolator(new DecelerateInterpolator());

        ValueAnimator stretchAnim1 = ObjectAnimator.ofFloat(newBall, "y", endY,

        endY + f);

        stretchAnim1.setDuration(duration/4);

        stretchAnim1.setRepeatCount(1);

        stretchAnim1.setInterpolator(new DecelerateInterpolator());

        stretchAnim1.setRepeatMode(ValueAnimator.REVERSE);

        ValueAnimator stretchAnim2 = ObjectAnimator.ofFloat(newBall, "height",

        newBall.getHeight(),newBall.getHeight() - );

        stretchAnim2.setDuration(duration/4);

        stretchAnim2.setRepeatCount(1);

        stretchAnim2.setInterpolator(new DecelerateInterpolator());

        stretchAnim2.setRepeatMode(ValueAnimator.REVERSE);

        ValueAnimator bounceBackAnim = ObjectAnimator.ofFloat(newBall, "y", endY,

        startY);

        bounceBackAnim.setDuration(duration);

        bounceBackAnim.setInterpolator(newDecelerateInterpolator());

        // Sequence the down/squash&stretch/upanimations

        AnimatorSet bouncer = new AnimatorSet();

        bouncer.play(bounceAnim).before(squashAnim1);

        bouncer.play(squashAnim1).with(squashAnim2);

        bouncer.play(squashAnim1).with(stretchAnim1);

        bouncer.play(squashAnim1).with(stretchAnim2);

        bouncer.play(bounceBackAnim).after(stretchAnim2);

        // Fading animation - remove the ball when theanimation is done

        ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);

        fadeAnim.setDuration();

        fadeAnim.addListener(new AnimatorListenerAdapter() {

        @Override

        public void onAnimationEnd(Animatoranimation) {

        balls.remove(((ObjectAnimator)animation).getTarget());

        }

        });

        // Sequence the two animations to play oneafter the other

        AnimatorSet animatorSet = new AnimatorSet();

        animatorSet.play(bouncer).before(fadeAnim);

        // Start the animation

        animatorSet.start();