精华内容
下载资源
问答
  • 我们以平移一个View展开来说: 调用ObjectAnimator.of...创建了一个ObjectAnimator对象,然后将传入的属性值保存下来,我们先看下anim.setFloatValues(values)里面具体干了什么 PropertyValuesHolder.ofFlo...

    相对于View动画,属性动画有很多好处,比如:可以对任何对象操作,解决动画后控件点击区域问题等等。

    我们以平移一个View展开来说:
    在这里插入图片描述
    调用ObjectAnimator.ofFloat时:
    在这里插入图片描述
    创建了一个ObjectAnimator对象,然后将传入的属性值保存下来,我们先看下anim.setFloatValues(values)里面具体干了什么
    在这里插入图片描述

    PropertyValuesHolder.ofFloat 里面会创建一个FloatPropertyValuesHolder
    在这里插入图片描述
    在这里插入图片描述
    看它的成员变量命名,不难猜到,就是利用PropertyValuesHolder来修改传入对象的属性的,具体实现是通过反射机制,通过拼接传入的属性名来反射到对应属性的set/get方法,感兴趣的可以看下完整代码,这里就不阐述了,以免脱离主线,陷入源码无法自拔。

    然后我们接着看ValueAnimator.setValues
    在这里插入图片描述
    PropertyValuesHolder存到HashMap中,key为propertyName, 以便取出对应属性的PropertyValuesHolder

    然后我们返回来看下ObjectAnimator构造方法里面干了什么
    在这里插入图片描述
    就是初始化了操作对象,操作对象的属性名

    到现在为止,ObjectAnimator的准备工作都做好了,然后就是调用start方法开始执行动画了
    在这里插入图片描述
    AnimationHandler这个类的作用我们稍后揭晓,我们先看下父类,也就是ValueAnimator的start实现
    在这里插入图片描述
    在这里插入图片描述
    首先会检测下执行start的线程是否属于Looper线程(这也暗示了,是消息循环来驱动更新属性值,从而产生动画效果的),然后就是一堆变量的初始化,随后,会调用addAnimationCallback
    在这里插入图片描述
    在这里插入图片描述
    ,再次看到了AnimationHandler,这个类是干什么用的呢?看类名,貌似是动画的处理者,我们看下类的实现
    在这里插入图片描述
    有个staticThreadLocal,负责存放对应Looper线程AnimationHandler,以便对应线程获取
    在这里插入图片描述
    在这里插入图片描述
    会维护一个Choreographer对象,看Choreographer类的实现,可以发现Looper,Handler,Message的痕迹,也验证了上文的推测:消息循环来驱动更新属性值。具体的实现这里就不阐述了。
    AnimationHandler的作用大致就是:建立与Choreographer的联系,从而接收到系统的帧绘制消息,然后转发回ValueAnimator,然后再通过PropertyValueHolder给对象设置新属性值,然后产生动画效果。

    驱动更新的位置找到了,那在什么位置更新对象的属性呢?
    在这里插入图片描述
    在这里插入图片描述
    我们可以看到,计算当前时间点属性值的任务也是PropertyValuesHolder完成的, ValueAnimator.animateValue负责调用计算当前属性值方法,然后ObjectAnimator自动将新属性值设置给当前对象。

    若有错误,欢迎指正!

    展开全文
  • 分析下面一段代码的逻辑 objectAnimator.start(); 他会调用父类的start(),即ValueAnimator,我们分析valueAnimator.start()即可 ValueAnimator: public void start() { start(false); } ...

    分析下面一段代码的逻辑

    objectAnimator.start();

    他会调用父类的start(),即ValueAnimator,我们分析valueAnimator.start()即可

    ValueAnimator:

    public void start() {
        start(false);
    }
    private void start(boolean playBackwards) {
    
           ...
    
            AnimationHandler animationHandler = getOrCreateAnimationHandler();
            animationHandler.mPendingAnimations.add(this);
    
            ...
    
            animationHandler.start();
        }

    ValueAnimator把动画逻辑交给了AnimationHandler。接着看animationHandler.start()

    ValueAnimator.AnimationHandler:

    public void start() {
                scheduleAnimation();
            }
    private void scheduleAnimation() {
                if (!mAnimationScheduled) {
                    mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimate, null);
                    mAnimationScheduled = true;
                }
            }
    mChoreographer是什么?这追溯到AnimationHandler的创建地方。
    首先看AnimationHandler创建的机制
    ValueAnimator:
    private static AnimationHandler getOrCreateAnimationHandler() {
            AnimationHandler handler = sAnimationHandler.get();
            if (handler == null) {
                handler = new AnimationHandler();
                sAnimationHandler.set(handler);
            }
            return handler;
        }
    protected static ThreadLocal<AnimationHandler> sAnimationHandler =
                new ThreadLocal<AnimationHandler>();

    所以一个线程中只有一个AnimationHandler。

    接着看AnimationHandler创建细节

    ValueAnimator.AnimationHandler:

    private AnimationHandler() {
                mChoreographer = Choreographer.getInstance();
            }

    接着看Choreographer:

    Choreographer:

    public static Choreographer getInstance() {
            return sThreadInstance.get();
        }
    private static final ThreadLocal<Choreographer> sThreadInstance =
                new ThreadLocal<Choreographer>() {
            @Override
            protected Choreographer initialValue() {
                Looper looper = Looper.myLooper();
                if (looper == null) {
                    throw new IllegalStateException("The current thread must have a looper!");
                }
                return new Choreographer(looper);
            }
        };

    可见Choreographer也是每个线程只有一个,而且他指明了只有在具有looper的线程下才能创建成功,这是因为他会创建一个handler

    Choreographer:

    private Choreographer(Looper looper) {
            mLooper = looper;
            mHandler = new FrameHandler(looper);
            
            ...
    
    
        }

    Choreographer.FrameHandler:

    private final class FrameHandler extends Handler {
            public FrameHandler(Looper looper) {
                super(looper);
            }
    
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MSG_DO_FRAME:
                        doFrame(System.nanoTime(), 0);
                        break;
                    case MSG_DO_SCHEDULE_VSYNC:
                        doScheduleVsync();
                        break;
                    case MSG_DO_SCHEDULE_CALLBACK:
                        doScheduleCallback(msg.arg1);
                        break;
                }
            }
        }

    我们再回头看看Choreographer是如何使动画跑起来的:

    Choreographer:

    public void postCallback(int callbackType, Runnable action, Object token) {
            postCallbackDelayed(callbackType, action, token, 0);
        }
    public void postCallbackDelayed(int callbackType,
                Runnable action, Object token, long delayMillis) {
            ...
    
            postCallbackDelayedInternal(callbackType, action, token, delayMillis);
        }
    private void postCallbackDelayedInternal(int callbackType,
                Object action, Object token, long delayMillis) {
           ...
    
            synchronized (mLock) {
                final long now = SystemClock.uptimeMillis();
                final long dueTime = now + delayMillis;
                mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
    
                if (dueTime <= now) {
                    scheduleFrameLocked(now);
                } else {
                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                    msg.arg1 = callbackType;
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtTime(msg, dueTime);
                }
            }
        }

    可以知道他把action存储到了mCallbackQueues数组中的下标为CALLBACK_ANIMATION(1)的CallbackQueue中。

    因为delayMillis为0,所以他会发送一个what为MSG_DO_SCHEDULE_CALLBACK的Message到mHandler去处理。

    根据上面的what分支看下去

    Choreographer:

    void doScheduleCallback(int callbackType) {
            synchronized (mLock) {
                if (!mFrameScheduled) {
                    final long now = SystemClock.uptimeMillis();
                    if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
                        scheduleFrameLocked(now);
                    }
                }
            }
        }
    private void scheduleFrameLocked(long now) {
            if (!mFrameScheduled) {
                mFrameScheduled = true;
                if (USE_VSYNC) {
                    if (DEBUG_FRAMES) {
                        Log.d(TAG, "Scheduling next frame on vsync.");
                    }
    
                    // If running on the Looper thread, then schedule the vsync immediately,
                    // otherwise post a message to schedule the vsync from the UI thread
                    // as soon as possible.
                    if (isRunningOnLooperThreadLocked()) {
                        scheduleVsyncLocked();
                    } else {
                        Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                        msg.setAsynchronous(true);
                        mHandler.sendMessageAtFrontOfQueue(msg);
                    }
                } else {
                    final long nextFrameTime = Math.max(
                            mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
                    if (DEBUG_FRAMES) {
                        Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
                    }
                    Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtTime(msg, nextFrameTime);
                }
            }
        }

    USE_VSYNC是垂直同步的意思,使得显卡生成帧的速度和屏幕刷新的速度的保持一致。在此不讨论其细节,假设不开启,因为,如果开启的话,后面的流程最终还是和不开启的流程一样的。

    接着看MSG_DO_FRAME分支

    Choreographer:

    void doFrame(long frameTimeNanos, int frame) {
            ...
    
            try {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
    
                mFrameInfo.markInputHandlingStart();
                doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
    
                mFrameInfo.markAnimationsStart();
                doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
    
                mFrameInfo.markPerformTraversalsStart();
                doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
    
                doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
    
            ...
        }
    void doCallbacks(int callbackType, long frameTimeNanos) {
            CallbackRecord callbacks;
            synchronized (mLock) {
                // We use "now" to determine when callbacks become due because it's possible
                // for earlier processing phases in a frame to post callbacks that should run
                // in a following phase, such as an input event that causes an animation to start.
                final long now = System.nanoTime();
                callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                        now / TimeUtils.NANOS_PER_MS);
                ...
            }
            try {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
                for (CallbackRecord c = callbacks; c != null; c = c.next) {
                    if (DEBUG_FRAMES) {
                        Log.d(TAG, "RunCallback: type=" + callbackType
                                + ", action=" + c.action + ", token=" + c.token
                                + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
                    }
                    c.run(frameTimeNanos);
                }
            } finally {
                synchronized (mLock) {
                    mCallbacksRunning = false;
                    do {
                        final CallbackRecord next = callbacks.next;
                        recycleCallbackLocked(callbacks);
                        callbacks = next;
                    } while (callbacks != null);
                }
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
        }

    首先取出CALLBACK_ANIMATION对应的CallbackQueue中的actions列表,然后运行。这样,我们就回到了刚开始使用Choreographer时传入的action。

    ValueAnimator.AnimationHandler:

    final Runnable mAnimate = new Runnable() {
                @Override
                public void run() {
                    mAnimationScheduled = false;
                    doAnimationFrame(mChoreographer.getFrameTime());
                }
            };
    void doAnimationFrame(long frameTime) {
                mLastFrameTime = frameTime;
    
                // mPendingAnimations holds any animations that have requested to be started
                // We're going to clear mPendingAnimations, but starting animation may
                // cause more to be added to the pending list (for example, if one animation
                // starting triggers another starting). So we loop until mPendingAnimations
                // is empty.
                while (mPendingAnimations.size() > 0) {
                    ArrayList<ValueAnimator> pendingCopy =
                            (ArrayList<ValueAnimator>) mPendingAnimations.clone();
                    mPendingAnimations.clear();
                    int count = pendingCopy.size();
                    for (int i = 0; i < count; ++i) {
                        ValueAnimator anim = pendingCopy.get(i);
                        // If the animation has a startDelay, place it on the delayed list
                        if (anim.mStartDelay == 0) {
                            anim.startAnimation(this);
                        } else {
                            mDelayedAnims.add(anim);
                        }
                    }
                }
    
                // Next, process animations currently sitting on the delayed queue, adding
                // them to the active animations if they are ready
                int numDelayedAnims = mDelayedAnims.size();
                for (int i = 0; i < numDelayedAnims; ++i) {
                    ValueAnimator anim = mDelayedAnims.get(i);
                    if (anim.delayedAnimationFrame(frameTime)) {
                        mReadyAnims.add(anim);
                    }
                }
                int numReadyAnims = mReadyAnims.size();
                if (numReadyAnims > 0) {
                    for (int i = 0; i < numReadyAnims; ++i) {
                        ValueAnimator anim = mReadyAnims.get(i);
                        anim.startAnimation(this);
                        anim.mRunning = true;
                        mDelayedAnims.remove(anim);
                    }
                    mReadyAnims.clear();
                }
    
                // Now process all active animations. The return value from animationFrame()
                // tells the handler whether it should now be ended
                int numAnims = mAnimations.size();
                for (int i = 0; i < numAnims; ++i) {
                    mTmpAnimations.add(mAnimations.get(i));
                }
                for (int i = 0; i < numAnims; ++i) {
                    ValueAnimator anim = mTmpAnimations.get(i);
                    if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {
                        mEndingAnims.add(anim);
                    }
                }
                mTmpAnimations.clear();
                if (mEndingAnims.size() > 0) {
                    for (int i = 0; i < mEndingAnims.size(); ++i) {
                        mEndingAnims.get(i).endAnimation(this);
                    }
                    mEndingAnims.clear();
                }
    
                ...
                if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
                    scheduleAnimation();
                }
            }

    ValueAnimator:

    private void startAnimation(AnimationHandler handler) {
            ...
            initAnimation();
            handler.mAnimations.add(this);
            ...
        }

    doAnimationFrame遍历mPendingAnimations,需要执行的ValueAnimator会添加到mAnimations中,遍历mAnimations,然后开始执行真正的动画操作

    ValueAnimator:

    final boolean doAnimationFrame(long frameTime) {
            ...
            return animationFrame(currentTime);
        }
    boolean animationFrame(long currentTime) {
            boolean done = false;
            switch (mPlayingState) {
            case RUNNING:
            case SEEKED:
                float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
                ...
                animateValue(fraction);
                break;
            }
    
            return done;
        }
    void animateValue(float fraction) {
            fraction = mInterpolator.getInterpolation(fraction);
            mCurrentFraction = fraction;
            int numValues = mValues.length;
            for (int i = 0; i < numValues; ++i) {
                mValues[i].calculateValue(fraction);
            }
            if (mUpdateListeners != null) {
                int numListeners = mUpdateListeners.size();
                for (int i = 0; i < numListeners; ++i) {
                    mUpdateListeners.get(i).onAnimationUpdate(this);
                }
            }
        }

    animateValue方法就是ValueAnimator的核心

    1. 首先根据当前的Interpolator得到对应的fraction。
    2. 然后遍历mValues,执行calculateValue。mValues是一个PropertyValuesHolder集合,PropertyValuesHolder存储着需要动态变化的信息,比如方法名的字符串对象"translationX",这就是我们平时ObjectAnimator.ofFloat提供的方法名啊。执行calculateValue就是利用反射来执行对应的方法(这个细节我还没有仔细看源码),实现真正的动画。
    3. 最后遍历监听器并回调。

    动画如何结束呢?我们看回去AnimationHandler的doAnimationFrame方法,里面有这么一段代码:

    ValueAnimator.AnimationHandler.doAnimationFrame:

    for (int i = 0; i < numAnims; ++i) {
                    ValueAnimator anim = mTmpAnimations.get(i);
                    if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {
                        mEndingAnims.add(anim);
                    }
                }
                mTmpAnimations.clear();
                if (mEndingAnims.size() > 0) {
                    for (int i = 0; i < mEndingAnims.size(); ++i) {
                        mEndingAnims.get(i).endAnimation(this);
                    }
                    mEndingAnims.clear();
                }

    ValueAnimator:

    protected void endAnimation(AnimationHandler handler) {
            handler.mAnimations.remove(this);
            handler.mPendingAnimations.remove(this);
            handler.mDelayedAnims.remove(this);
            mPlayingState = STOPPED;
            mPaused = false;
            ...
        }

    可见,一个动画如果没有完成就不会添加到mEndingAnims列表,一旦完成了就会加入,并且会被删除掉。自然这个动画就算结束了。

    mAnimations只要不为空,那么就会再次调用scheduleAnimation(),如下

    ValueAnimator.AnimationHandler.doAnimationFrame:

    if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
                    scheduleAnimation();
                }

    总结一下:

    1. ValueAnimator创建时,会获取到本线程的一个AnimationHandler,里面包含一个本线程的Choreographer,Choreographer又包含一个handler(所以要求ValueAnimator创建所在的线程必须是具有looper的)。
    2. ValueAnimator通过AnimationHandler执行动画,AnimationHandler又通过Choreographer中的handler进行不断的回调,ValueAnimator收到回调后利用反射机制执行动画操作。
    3. ObjectAnimator作用的对象如果只能在特定的线程里面操作,ObjectAnimator必须在特定的线程创建,这样才能在特定的线程得到Choreographer中的handler的回调。(比如View只能在主线程操作UI更新)

    转载于:https://www.cnblogs.com/linyibiao/p/5472276.html

    展开全文
  • ObjectAnimator详解

    万次阅读 2017-06-15 15:50:12
    ObjectAnimator继承自ValueAnimator,所以ValueAnimator所能使用的方法,ObjectAnimator都可以使用,ObjectAnimator同时也重写了几个方法,比如:ofInt() ofFloat()等基本使用

    ObjectAnimator继承自ValueAnimator,所以ValueAnimator所能使用的方法,ObjectAnimator都可以使用,ObjectAnimator同时也重写了几个方法,比如:ofInt() ofFloat()等

    基本使用

    //第一个参数:指定执行动画的控件,第二个参数:指定控件的属性,第三个参数是可变长参数
    public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) 
    //透明度动画
    ObjectAnimator animator = ObjectAnimator.ofFloat(view,"alpha",1,0,1);  
    animator.setDuration(2000);  
    animator.start(); 
    
    //旋转动画:围绕x轴旋转
    ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationX",0,270,0);  
    animator.setDuration(2000);  
    animator.start();
    
    //旋转动画:围绕y轴旋转
    ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationY",0,180,0);  
    animator.setDuration(2000);  
    animator.start();
    
    //旋转动画:围绕z轴旋转
    ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotation",0,270,0);  
    animator.setDuration(2000);  
    animator.start();  
    
    //平移动画:在x轴上平移
    ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "translationX", 0, 200, -200,0);  
    animator.setDuration(2000);  
    animator.start(); 
    
    //平移动画:在y轴上平移
    ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "translationY", 0, 200, -100,0);  
    animator.setDuration(2000);  
    animator.start(); 
    
    //缩放动画:在x轴缩放
    ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleX", 0, 3, 1);  
    animator.setDuration(2000);  
    animator.start();
    
    //缩放动画:在y轴上缩放
    ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleY", 0, 3, 1);  
    animator.setDuration(2000);  
    animator.start(); 

    ObjectAnimator动画原理

    这里写图片描述
    ObjectAnimator动画原理:如上图最后一步,根据属性值拼装成对应的set函数的名字,比如”scaleY”的拼接方法就是将属性的第一个字母强制大写后,与set拼接,也就是setScaleY,然后通过反射找到对应控件的setScaleY(float scaleY)函数,将当前数字值作为setScaleY(float scale)的参数将其传入。属性值得首字母大小写都可以,最终都会被强转成大写。View中都已经实现了相关的alpha rotation translate scale相关的set方法。

    自定义ObjectAnimator属性

    这里写图片描述

       ObjectAnimator objectAnimator = ObjectAnimator.ofInt(mCircleView,"pointRadius",0,200,100,200,50);
            objectAnimator.setDuration(1000);
            objectAnimator.start();

    自定义Point

    public class Ponit {
        private int mRadius;
    
        public Ponit() {
        }
    
        public Ponit(int mRadius) {
            this.mRadius = mRadius;
        }
    
        public int getRadius() {
            return mRadius;
        }
    
        public void setRadius(int mRadius) {
            this.mRadius = mRadius;
        }
    }
    

    自定义view

    public class CircleView extends View {
        private Ponit mCurrentPoint = new Ponit();
        private Paint mPiant ;
        private int mScreenWidth;//屏幕宽度
        public CircleView(Context context) {
            this(context,null);
        }
    
        public CircleView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public CircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mPiant = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPiant.setColor(Color.RED);
            mPiant.setStyle(Paint.Style.FILL);
            mScreenWidth = ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            if (mCurrentPoint != null){
                canvas.drawCircle(mScreenWidth/2,getY()+getPaddingTop(),mCurrentPoint.getRadius(),mPiant);
            }
        }
        public int getPointRadius(){  //这个get方法只作为默认值出现在这里的
            return 50;  
        }  
        public void setPointRadius(int radius){//这里set方法必须和ObjectAnimator中的属性值对应
            mCurrentPoint.setRadius(radius);
            invalidate();
        }
    }

    ObjectAnimator改变控件背景颜色

    以TextView为类,改变其背景颜色,关键方法是继承View的控件都实现了这个方法

    public void setBackgroundColor(int color); 

    这里写图片描述

     ObjectAnimator objectAnimator = ObjectAnimator.ofInt(tv,"backgroundColor",0xfff10f0f,0xff0f94f1,0xffeaf804,0xfff92a0f);
            objectAnimator.setDuration(2000);
            objectAnimator.setEvaluator(new ArgbEvaluator());
            objectAnimator.start();
    展开全文
  • ObjectAnimator使用

    2019-05-30 12:45:09
    为了使动画直接与对应的控件相关联,以使我们从监听动画过程中解放出来,Google工程师在ValueAnimator的基础上派生了一个类ObjectAnimator,派生类的特性相信大家都知道。 但是ObjectAnimator也重写...
    • 上次学习了ValueAnimator,但是ValueAnimator只能对动画中的数值进行计算,如果那个控件执行操作,就要实现对该对象的监听,相比于补间动画比较繁琐
    • 为了使动画直接与对应的控件相关联,以使我们从监听动画过程中解放出来,Google工程师在ValueAnimator的基础上派生了一个类ObjectAnimator,派生类的特性相信大家都知道。
    • 但是ObjectAnimator也重写了几个函数,比如ofInt() ofFloat()等。
    //第一个参数指定这个动画要操作的控件
    //第二个参数用于指定这个动画要操作控件的哪一个属性
    第三个参数是可变长参数,是指这个属性值如何变化
    ObjectAnimator animator = ObjectAnimator.ofFloat(textView,"alpha", 1, 0, 1);
    animator.setDuration(2000);
    animator.start();
    
    • 但是它是如何通过第二个参数实现的控件的动画效果呢:
      • 在我们指定控件的动画的时候,ObjectAnimator会在TextView中去找对应的set函数,这些函数都是从View中继承来的,在View中有关动画的函数如下:
    函数作用方法
    设置透明度public void setAlpha(float alpha)
    设置绕Z轴旋转度数public void setRotation(float rotation)
    设置绕X轴旋转度数public void setRotationX(float rotationX)
    设置绕Y轴旋转度数public void setRotationY(float rotationY)
    在X轴上平移(控件为原点向右为正方向)public void setTranslationX(float translationX)
    在Y轴上平移(控件为原点向下为正方向)public void setTranslationY(float translationY)
    在X轴上缩放public void setScaleX(flaot scaleX)
    在Y轴上缩放public void setScaleY(float scaleY)
    • 注意:

      • 如果使用ObjectAnimator来进行自定义动画,在要操作的控件中必须存在对应属性的set函数,而且参数类型必须与构造所使用的ofFloat()或者ofInt()函数一致
      • set函数必须使用驼峰命名法,再通过反射找到相应的set方法。
    • ObjectAnimator动画原理:
      在这里插入图片描述

    • 从图中我们可以看出ObjectAnimator的set相当于监听器的功能,但是相应的控件操作还是需要自己实现

    • 首先我们看一下setScaleY()是如何实现的

    public void setScaleY(float scaleY) {
        if (scaleY != getScaleY()) {
            scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY");
            invalidateViewProperty(true, false);
            mRenderNode.setScaleY(scaleY);
            invalidateViewProperty(false, true);
    
    
            invalidateParentIfNeededAndWasQuickRejected();
            notifySubtreeAccessibilityStateChangedIfNeeded();
        }
    }
    
    • 自定义ObjectAnimator属性:
      • 三个构造函数:
    public static ObjectAnimator ofFloat(Object target, String propertyName,float... values);
    public static ObjectAnimmator ofInt(Object target, String propertyName, int... values);
    public static ObjectAnimator ofObject(Object target, String propertyName, TypeEvaluator evaluator, Object... values);
    
    • 相比于ValueAnimator, ObjectAnimator的每个构造函数中多了一个propertyName属性,用于指定所要操作的属性

    • 使用流程:

      • 比如自定义一个动画,首先要实现setXXX函数
      • 接着如果有Evaluator就实现一个Evaluator
      • 之后调用相应的构造函数,使得其中Evaluator负责返回相应的数值
      • 数值返回给setXXX函数,从而改变相应的位置
    • 有了set函数那么何时能调用他的get函数:

      • 当我们给动画值设定一个值的时候,他才会调用属性对应的get函数来得到动画初始值,如果没有初始值,系统会自动调用默认值
      • 如果是 ofInt()或者是ofFloat()可以使用默认值0,0.0f, 但是如果使用的是自定义动画比如Point类型,就不存在系统的默认值,所以就会报错
    展开全文
  • 本文出自【赵彦军的博客】 文章目录ObjectAnimator参考资料 ObjectAnimator public final class ObjectAnimator extends ...ObjectAnimator 继承 ValueAnimator , 所以 ObjectAnimator 拥有 ValueAnimator 一切.
  • 1 ObjectAnimator 概述 前面讲解了ValueAnimator和估值器,ValueAnimator只能对数值进行计算,要实现动画需要监听动画,然后获取数值,自己操作对象。不知道大家的感觉如何,我有两个两个感觉,一是这个动画有点...
  • 一.概述 之前讲了ValueAnimator,但是有...为了能让动画直接与对应控件相关联,以使我们从监听动画过程中解放出来,谷歌的开发人员在ValueAnimator的基础上,又派生了一个类ObjectAnimator。 由于ObjectAnimator是...
  • ObjectAnimator的基本用法和工作原理在上一篇文章当中都已经讲解过了,相信大家都已经掌握。那么大家应该都还记得,我们在吐槽补间动画的时候有提到过,补间动画是只能实现移动、缩放、旋转和淡入淡出这四种动画操作...
  • 前言属性动画的使用 是 Android 开发中常用的知识今天,我将讲解属性动画使用中最核心的一个方法类:ObjectAnimator,希望你们会喜欢。目录示意图储备知识1. 简介实现属性动画中的一个核心方法类继承自ValueAnimator...
  • ObjectAnimator是派生自ValueAnimator的,所以ValueAnimator中所能使用的方法,在ObjectAnimator中都可以正常使用。  但ObjectAnimator也重写了几个方法,比如ofInt(),ofFloat()等。 二.ObjectAnimator的初步使用 ...
  • Animation动画——ObjectAnimator基本使用

    千次阅读 2018-10-08 15:59:35
    一、概述 1、引入 上几篇给大家讲了ValueAnimator,但...为了能让动画直接与对应控件相关联,以使我们从监听动画过程中解放出来,谷歌的开发人员在ValueAnimator的基础上,又派生了一个类ObjectAnimator...
  • 利用ObjectAnimator重写的ofFloat方法如何实现一个动画: (改变透明度) public static ObjectAnimator ofFloat(Object target, String propertyName, float... values)  第一个参数...
  • 入口1: ObjectAnimator anim = ObjectAnimator.ofInt(foo, "alpha", 1, 100); 入口2: anim.setDuration(1000); anim.start(); 二.实现 0.ObjectAnimator继承ValueAnimator 1.入口1: ObjectAnimator ...
  • 1. 概述 1.1 前言 ValueAnimator有个缺点,只能对...ObjectAnimator是派生自ValueAnimator的,所以ValueAnimator中所能使用的方法,在ObjectAnimator中都可以正常使用。 ObjectAnimator重写了几个方法,例如ofInt...
  • 本周做一个动画的时候用到了ObjectAnimator,动画要求,一个柱状图根据数值的不同慢慢升起,但是使用了ObjectAnimator类的时候,发现该类并不能满足我的需求,后来使用了它的父类ValueAnimator,十分简单的解决了这...
  • 布局就是一个ImageView,看看实现代码 public void flip(View view) { ObjectAnimator visibleToInVisable = ObjectAnimator.ofFloat(mImageView, "rotationX", 0.0f, 360.0f); //设置插值器 visibleToInVi
  • Android ObjectAnimator基本使用

    千次阅读 2017-11-06 14:22:29
    3、ObjectAnimator动画原理 我们先来看张图:   在这张图中,将ValueAnimator的动画流程与ObjectAnimator的动画流程做了个对比。   可以看到ObjectAnimator的动画流程中,也是首先通过...
  • ValueAnimator是监听动画的过程,自己实现属性的改变,详见《 Android属性动画之ValueAnimator》,但是ObjectAnimator就有所不同,它继承了ValueAnimator,它真正可以作用在一个对象上,并且明确的指定了要更改的...
  • android属性动画是开发中经常使用的一项技能,但是我之前却从没有深究过动画实现原理,本文基于android 8.0,撸了一把ObjectAnimator源码,分析属性动画执行关键的过程。 一、动画执行的两个主要的问题 动画每一...
  • 今天,我将讲解属性动画使用中最核心的一个方法类:ObjectAnimator,希望你们会喜欢。
  • 属性动画的集成关系 Paste_Image.png ...ObjectAnimator animator=ObjectAnimator.ofFloat(image,"rotationX",0f,360f); animator.setDuration(2000);//执行时间 animator.setInterpolator(new Li
  • 好了,在知道了ObjectAnimator原理以后,下面就来看看如何自定义一个ObjectAnimator的属性吧。 二、自定义ObjectAnimator属性 上面我们已经看了使用View自带的set函数所对应属性的方法,而且理解了...
  • ObjectAnimator 是直接对某个view进行更改。 ValueAnimator 根据 TimeInterpolator 在不断产生相应的数据,来传进view ,view自己做改变。 介绍: 属性动画是通过改变某个控件的属性值来创造动画,比如在规定的...
  • 本文将详细介绍 Android 动画中 属性动画的原理 & 使用 简介 具体使用 而我们主要使用的就是ValueAnimator和ObjectAnimator类 ValueAnimator:可以设置开始值和结束值来动态改变view的移动位置 ObjectAnimator...
  • 介绍ObjectAnimator是派生自ValueAnimator的。所以ValueAnimator中所能使用的方法,在ObjectAnimator中都可以正常使用。但是已经有个ValueAnimator为什么还要加入ObjectAnimator.因为ValueAnimator是通过调用监听,...
  • 属性动画的工作原理就不说了,详情的大家可以看官网 Android Developers 地址 动画的API 地址如果有忘记的属性可以点击查看 ObjectAnimator 的介绍: A subclass of ValueAnimator that allows you to set a ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,466
精华内容 1,386
关键字:

objectanimator原理