NineOldAnimations design analysis, interior design style analysis

Source: Internet
Author: User

NineOldAnimations design analysis, interior design style analysis
NineOldAnimations Design Analysis 1. Function Introduction

NineOldAndroids is a framework that supports Android attribute animation and 3D Rotation animation in earlier versions (under api 11). It provides a series of functions such as ViewAnimator, ObjectAnimator, viewPropertyAnimator and other APIs are used to complete these animations, solving the compatibility problem of the Android animation framework in earlier versions. After api 11 (Honeycomb (Android 3.0), Android released animation effects such as property animation and X axis flip, but these effects cannot run below api 11, the emergence of NineOldAndroids allows these animations to be compatible with systems of lower versions, ensuring that the animations can run perfectly in various system versions.

2. Overall Design


The above is the overall NineoldAnimations design. Animator uses PropertyValuesHolder to update the object's target attributes. If the user does not set the Property object of the target Property, the setter method of the target Property is called in the form of reflection to update the Property value; otherwise, the Property value is set through the set method of the Property. This attribute value is calculated by KeyFrameSet, and KeyFrameSet is calculated by time interpolation and type estimator. During the animation execution, the target attribute value is constantly calculated at the current time point, and then the attribute value is updated to achieve the animation effect.
This article introduces NineOldAnimations in terms of the overall structure. If you need to analyze the source code, see NineOldAnimations source code analysis.

2.1 class details

Before proceeding to the next analysis, let's take a look at some core classes in NineOldAndroids and their functions.
*ValueAnimator: This class is a subclass of Animator and implements the entire animation processing logic. It is also the core class of NineOldAndroids;
*ObjectAnimator: Operation class of the Object Property animation, inherited from ValueAnimator, through which the object property is operated in the form of animation;
*TimeInterpolator: Time interpolation tool, which is used to calculate the percentage of changes in the current attribute value based on the percentage of time elapsed. The system preset LinearInterpolator (linear interpolation tool: constant speed animation) accelerateDecelerateInterpolator (acceleration and deceleration interpolation tool: slow and fast between the two ends of the animation) and DecelerateInterpolator (deceleration interpolation tool: slower and slower animation;
*TypeEvaluator: The Chinese Translation of TypeEvaluator is a type valuation algorithm. It is used to calculate the changed attribute value based on the percentage of changes in the current attribute. the preset system includes IntEvaluator (for integer attributes) floatEvaluator (for floating point attributes) and ArgbEvaluator (for Color attributes );
*Property: Attribute object, which defines the set and get methods of the attribute;
*PropertyValuesHolder: PropertyValuesHolder is a class that holds the target Property, setter, getter method, and key frame set.
*KeyframeSet: Stores a set of key frames for an animation;
*AnimationProxy: Use the property animation helper class of View under API 11.

2.2 Basic use

Example 1:
Change the translationY attribute of an object (myObject) and move it up along the Y axis for a distance: its height. The animation is completed within the default time, And the animation completion time can be defined, for more flexible effects, we can also define interpolation and valuation algorithms, but generally we do not need to customize them. The system has already preset some to meet the needs of common animations.

ObjectAnimator.ofFloat(myObject, "translationY", -myObject.getHeight()).start();  

Example 2:
Change the background color attribute of an object. A typical scenario is to change the background color of the View. The following animation allows the gradient of the background color from 0xFFFF8080 to 0xff80ff in three seconds, in addition, the animation will have infinite loops and will have a reverse effect.

ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", /*Red*/0xFFFF8080, /*Blue*/0xFF8080FF);  colorAnim.setDuration(3000);  colorAnim.setEvaluator(new ArgbEvaluator());  colorAnim.setRepeatCount(ValueAnimator.INFINITE);  colorAnim.setRepeatMode(ValueAnimator.REVERSE);  colorAnim.start();  

Example 3:
The animation set changes the rotation, translation, scaling, and transparency of the View within 5 seconds.

AnimatorSet set = new AnimatorSet();  set.playTogether(      ObjectAnimator.ofFloat(myView, "rotationX", 0, 360),      ObjectAnimator.ofFloat(myView, "rotationY", 0, 180),      ObjectAnimator.ofFloat(myView, "rotation", 0, -90),      ObjectAnimator.ofFloat(myView, "translationX", 0, 90),      ObjectAnimator.ofFloat(myView, "translationY", 0, 90),      ObjectAnimator.ofFloat(myView, "scaleX", 1, 1.5f),      ObjectAnimator.ofFloat(myView, "scaleY", 1, 0.5f),      ObjectAnimator.ofFloat(myView, "alpha", 1, 0.25f, 1)  );  set.setDuration(5 * 1000).start();  

Example 4:
The following is a simple call method. The animate method is unique to nineoldandroids. The animation lasts for 2 seconds, rotates 720 degrees on the Y axis, and translates the animation to the (100,100) position.

Button myButton = (Button)findViewById(R.id.myButton);  animate(myButton).setDuration(2000).rotationYBy(720).x(100).y(100);    
3. flowchart 3.1 ValueAnimator Flowchart

3.2 ObjectAnimator flowchart of View

4. Detailed Design

4.1 Core Principles 4.1.1 ValueAnimator. java

ObjectAnimator is a subclass of ValueAnimator. ObjectAnimator is responsible for property animation. However, the class that really operates on animation is actually ValueAnimator. It defines the execution logic of nineoldandroids and is one of the core of nineoldandroids.
When an animation is started, the animation itself will be added to the animation queue waiting for execution (sPendingAnimations), and then an ANIMATION_START message will be sent through the AnimationHandler to notify nineoldandroids to start the animation.

    private void start(boolean playBackwards) {        if (Looper.myLooper() == null) {            throw new AndroidRuntimeException("Animators may only be run on Looper threads");        }        // ......        sPendingAnimations.get().add(this);        // ......         AnimationHandler animationHandler = sAnimationHandler.get();        if (animationHandler == null) {            animationHandler = new AnimationHandler();            sAnimationHandler.set(animationHandler);        }        animationHandler.sendEmptyMessage(ANIMATION_START);    }

AnimationHandler is an internal class of ValueAnimator. It is responsible for processing the continuous execution of animations.

Private static class AnimationHandler extends Handler {@ Override public void handleMessage (Message msg) {boolean callAgain = true; ArrayList <ValueAnimator> animations = sAnimations. get (); ArrayList <ValueAnimator> delayedAnims = sDelayedAnims. get (); switch (msg. what) {case ANIMATION_START: ArrayList <ValueAnimator> pendingAnimations = sPendingAnimations. get (); // start the animation in the waiting queue, and then enter the ANIMATION_FRAME to execute the case ANIMATION_FRAME loop: // determine whether to start the animation in the waiting state based on the start time, if an animation has been started, calculate the attribute value that the animation should obtain at the moment based on the time point, and follow the new attribute. If the animation is not completed at this time, then, an ANIMATION_FRAME message will be published to enter the code segment here. // This is equivalent to executing the animation cyclically until the animation is completed }}}

As mentioned earlier, if it is an attribute animation and the system is lower than API 11, the attribute animation effect will be processed in the form of matrix transformation; otherwise, the setter method of the target object will be called in the form of set + attribute name to update the attribute value. The compatibility issue of this version will be handled during the initialization of the animation. The function that handles this issue is included in initAnimation of ObjectAnimator.

@ Override void initAnimation () {if (! MInitialized) {// note that if (mProperty = null) & AnimatorProxy. NEEDS_PROXY & (mTarget instanceof View) & PROXY_PROPERTIES.containsKey (mPropertyName) {setProperty (PROXY_PROPERTIES.get (mPropertyName);} int numValues = mValues. length; for (int I = 0; I <numValues; ++ I) {mValues [I]. setupSetterAndGetter (mTarget);} super. initAnimation ();}}

The property animation for packaging is mainly the alpha, zoom, pan, rotation, and other major animations of the View. If it is another type object, it will be accessed through the setter and getter methods of the Target attribute in the object. For example, the object type is a custom MyCustomButton, it has a property of myText. When you modify it through property animation, You need to define its setter and getter methods, such as setMyText and getMyText, in this way, nineoldanimations calls the setter method to update object attributes during animation execution.

4.1.2 ObjectAnimator. java

ObjectAnimator is an entry class for property animation. You can use the above static factory functions to construct ObjectAnimator. After setting the basic attributes, you need to set other attributes such as the animation execution time and repetition mode (optional ).
In the above static functions, parameter 1 is the target object to be animated, parameter 2 is the name of the attribute to be operated, and parameter 3 is the value range of the Target attribute, if a value is passed, the value is the final value of the Target attribute. If two values are passed, the first value is the starting value and the second value is the final value.

(1) Main Functions

    public static ObjectAnimator ofInt(Object target, String propertyName, int... values) ;    public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> property, int... values) ;    public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) ;    public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,            float... values) ;    public static ObjectAnimator ofObject(Object target, String propertyName,            TypeEvaluator evaluator, Object... values) ;
4.1.3 KeyFrameSet. java

When an animation is running, the key frame set class calculates the latest value of the current time target attribute based on the fraction and type estimator, then, the value is set to the target object through the set method of reflection or Property. The following is the calculation function for obtaining the current attribute value.

    public Object getValue(float fraction) {        // Special-case optimization for the common case of only two keyframes        if (mNumKeyframes == 2) {            if (mInterpolator != null) {                fraction = mInterpolator.getInterpolation(fraction);            }            return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),                    mLastKeyframe.getValue());        }        if (fraction <= 0f) {            final Keyframe nextKeyframe = mKeyframes.get(1);            final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();            if (interpolator != null) {                fraction = interpolator.getInterpolation(fraction);            }            final float prevFraction = mFirstKeyframe.getFraction();            float intervalFraction = (fraction - prevFraction) /                (nextKeyframe.getFraction() - prevFraction);            return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),                    nextKeyframe.getValue());        } else if (fraction >= 1f) {            final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);            final /*Time*/Interpolator interpolator = mLastKeyframe.getInterpolator();            if (interpolator != null) {                fraction = interpolator.getInterpolation(fraction);            }            final float prevFraction = prevKeyframe.getFraction();            float intervalFraction = (fraction - prevFraction) /                (mLastKeyframe.getFraction() - prevFraction);            return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),                    mLastKeyframe.getValue());        }        Keyframe prevKeyframe = mFirstKeyframe;        for (int i = 1; i < mNumKeyframes; ++i) {            Keyframe nextKeyframe = mKeyframes.get(i);            if (fraction < nextKeyframe.getFraction()) {                final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();                if (interpolator != null) {                    fraction = interpolator.getInterpolation(fraction);                }                final float prevFraction = prevKeyframe.getFraction();                float intervalFraction = (fraction - prevFraction) /                    (nextKeyframe.getFraction() - prevFraction);                return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),                        nextKeyframe.getValue());            }            prevKeyframe = nextKeyframe;        }        // shouldn't reach here        return mLastKeyframe.getValue();    }
4.1.4 PropertyValuesHolder. java

PropertyValuesHolder is a class that holds the target Property, setter, getter method, and key frame set. If the mProperty without attributes is not empty, for example, if you use a built-in Property or custom implementation Property, and set it to an animation class, when an animation is updated, the Property value is updated using the set method of the Property object. Otherwise, during initialization, PropertyValuesHolder assembles the setter and getter functions of the attribute (note that the setter and the set Method of the Property object mentioned above are two different things ), then, check whether the target object contains these methods. If so, get setter and getter.

Void setupSetter (Class targetClass) {mSetter = timer (targetClass, delimiter, "set", mValueType);} // calculate the value void calculateValue (float fraction) {mAnimatedValue = mKeyframeSet. getValue (fraction );}//...... void setAnimatedValue (Object target) {if (mProperty! = Null) {// get the new value, and update the value mProperty through the set method of Property. set (target, getAnimatedValue ();} // if no Property is set, call the update if (mSetter! = Null) {try {mTmpValueArray [0] = getAnimatedValue (); mSetter. invoke (target, mTmpValueArray);} catch (InvocationTargetException e) {Log. e ("PropertyValuesHolder", e. toString ();} catch (IllegalAccessException e) {Log. e ("PropertyValuesHolder", e. toString ());}}}

When executing an animation, use the interpolation and type estimator in the key frame to calculate the latest attribute values (see the calculatVealue function ), then, call the setter method or the set method of the Property object through reflection to set the target object to update the target Property. This process is executed cyclically to achieve the animation effect.

5. Miscellaneous

NineoldAnimations is always quite good and plays a major role in the development process. But from the design point of view, it may not be particularly good. For example, the Code is filled with warnings that do not perform type checks, or the library itself may have too many variability, this makes it difficult to be comprehensive.
The project has already been marked as DEPRECATED. The author's original intention should not update the library because it is already stable. I hope that friends will not mistakenly think that this library is no longer recommended.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.