1. Android Animation Category:

  • The View animation
  • The frame of animation
  • Attribute animation
1. View the animation
  1. The object of the View animation is the View
  2. View animation is the animation of the View image, does not really change the View state (such as View visibility,View position, etc.).
    • Sometimes the View cannot be hidden after the animation is completed, that is, view.setvisibility (view.gone) fails. In this case, call view.clearAnimation() to clear the View animation.
  3. There are four types of View animations
    • TranslateAnimation
    • ScaleAnimation
    • RotateAnimation
    • Transparency animation AlphaAnimation
  4. View animation methods
    • setFillBefore
      • View Whether to return to the state before the animation started after the animation ends
    • setFillEnabled
      • The test results are the same as setFillBefore
    • setFillAfter
      • View remains in the state at the end of the animation after the animation ends
    • SetZAdjustment: What was not tested
    • Sethasround Corners: Don’t know how to use it
    • <View
          android:id="@+id/v1"
          android:layout_width="200dp"
          android:layout_height="200dp"
          android:background="@color/colorPrimary"
          />
      <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:orientation="horizontal"
          android:gravity="center_vertical"
          android:background="@android:color/transparent"
          >
          <Button
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_weight="1.0"
              android:layout_margin="2dp"
              android:background="@color/colorAccent"
              android:text="setFillAfter true"
              android:onClick="setFillAfterTrue"
              />
          <Button
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_weight="1.0"
              android:layout_margin="2dp"
              android:background="@color/colorAccent"
              android:text="setFillBefore true"
              android:onClick="setFillBeforeTrue"
              />
          <Button
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_weight="1.0"
              android:layout_margin="2dp"
              android:background="@color/colorAccent"
              android:text="setFillEnabled true"
              android:onClick="setFillEnabledTrue"
              />
      </LinearLayout>
      Copy the code
      private ScaleAnimation gainScaleAnimation(a){
          ScaleAnimation scaleAnimation = new ScaleAnimation(0.5 F.1.5 F.0.5 F.1.5 F);
          scaleAnimation.setDuration(4000);
          return scaleAnimation;
      }
      public void setFillAfterTrue(View view) {
          v1.clearAnimation();
          ScaleAnimation scaleAnimation = gainScaleAnimation();
          // Using setFillAfter(true) alone and setFillAfter(true) + setFillEnabled(true),
          // The effect is the same, keeping the state at the end of the animation
          scaleAnimation.setFillAfter(true);
          scaleAnimation.setFillEnabled(true);
          v1.startAnimation(scaleAnimation);
      }
      public void setFillBeforeTrue(View view) {
          v1.clearAnimation();
          ScaleAnimation scaleAnimation = gainScaleAnimation();
          scaleAnimation.setFillBefore(true);
          v1.startAnimation(scaleAnimation);
      }
      public void setFillEnabledTrue(View view) {
          v1.clearAnimation();
          ScaleAnimation scaleAnimation = gainScaleAnimation();
          scaleAnimation.setFillEnabled(true);
          v1.startAnimation(scaleAnimation);
      }
      Copy the code
  5. TimeInterpolator/interpolator
    • A time interpolator defines the rate of change of an animation.
    • The interpolator defines the corresponding relationship between animation execution time and animation execution completion. Android provides multiple implementations without going into detail.
  6. View animation special use scene
    1. LayoutAnimation/ LayoutAnimation
      • LayoutAnimation is used to add exit effects to the child views of a ViewGroup.
      • LayoutAnimation can be implemented in XML or Java code
        // By referencing the LayoutAnimation defined under the Anim folder in the layout file<layoutAnimation 
            android:delay="500"
            android:animation="@anim/customanim"
            android:animationOrder="normal"
            xmlns:android="http://schemas.android.com/apk/res/android" />
        <ListView
            *
            android:layoutAnimation="@anim/anim_layout"/>
        Copy the code
        / / by LayoutAnimationController ViewGroup layout animation
        ListView lv;
        Animation anim = AnimationUtils.loadAnimation(this,R.anim.customanim);
        LayoutAnimationController controller = new LayoutAnimationController(anim);
        controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
        lv.setLayoutAnimation(controller);
        Copy the code
      • With XML, or by the Java code implementation, essence is through LayoutAnimationController. ViewGroup ViewGroup
        public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
            initViewGroup();
            // Parse the attributes set in the XML
            initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
        }
        private void initFromAttributes(
            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {* * */ / XML parsing to set the android: layoutAnimation, generate LayoutAnimationController instance, perform setLayoutAnimation
            case R.styleable.ViewGroup_layoutAnimation:
                int id = a.getResourceId(attr, -1);
                if (id > 0) {
                    setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
                }
                break; * * *}public void setLayoutAnimation(LayoutAnimationController controller) {
            mLayoutAnimationController = controller;
            if(mLayoutAnimationController ! =null) { mGroupFlags |= FLAG_RUN_ANIMATION; }}Copy the code
      • By default, LayoutAnimation provides three sub-animation sequences: sequential /normal, reverse /reverse, and random /random.
      • LayoutAnimationController by performing getTransformedIndex obtain the moment for which the index value corresponding Item implement animation.
      • By overriding getTransformedIndex, we can animate the ViewGroup layout in any order.
        • Making custom LayoutAnimationController
    2. The switching effect of the Activity
      • overridePendingTransition(int enterAnim, int exitAnim)
      • OverridePendingTransition must sits behind startActivity or finish, or not to take effect.
2. The frame animation
  1. Frame animation is a sequence of predefined images played in sequence, similar to movie playback.

  2. It can be created using XML or Java code

    // Create animation-list under drawable folder
            
    <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
        android:oneshot="false">
        <item
            android:drawable="@mipmap/ii1"
            android:duration="@android:integer/config_shortAnimTime" />
        <item
            android:drawable="@mipmap/ii2"
            android:duration="@android:integer/config_shortAnimTime" />
        <item
            android:drawable="@mipmap/ii3"
            android:duration="@android:integer/config_shortAnimTime" />
        <item
            android:drawable="@mipmap/ii4"
            android:duration="@android:integer/config_shortAnimTime" />
        <item
            android:drawable="@mipmap/ii5"
            android:duration="@android:integer/config_shortAnimTime" />
    </animation-list>// Reference in the layout file<View
        android:id="@+id/v1"
        android:layout_width="500px"
        android:layout_height="500px"
        android:background="@drawable/bg_animation_list"
        />View v1 = findViewById(r.i.v.1); //1: The AnimationDrawable specified in XML needs to be manually enabled ((AnimationDrawable)v1.getBackground()).start();Copy the code
    View v2 = findViewById(R.id.v2);
    AnimationDrawable anim = new AnimationDrawable();
    anim.setOneShot(false);
    anim.addFrame(getResources().getDrawable(R.mipmap.ii1),200);
    anim.addFrame(getResources().getDrawable(R.mipmap.ii2),200);
    anim.addFrame(getResources().getDrawable(R.mipmap.ii3),200);
    anim.addFrame(getResources().getDrawable(R.mipmap.ii4),200);
    anim.addFrame(getResources().getDrawable(R.mipmap.ii5),200);
    v2.setBackgroundDrawable(anim);
    anim.start();
    Copy the code

  3. For AnimationDrawable, even if the animation-list defined in the drawable file is referenced in the layout file XML, it needs to be manually enabled in Java code to execute the animation!

  4. Frame animation is easy to appear OOM when it uses many pictures, so avoid it as far as possible. If you must, you can use the following optimization scheme

    • Android AnimationDrawable Frame animation OOM problem optimization
    • Android performance optimization | animation to OOM? Optimized SurfaceView resolution for frame animation frame by frame
    • A larger Android performance optimization | do animation to caton? Optimized SurfaceView sliding window frame multiplexing for frame animation
    // Write a simple example of this
    public class AnimationsContainer {
        private Context context = null;
        private int arraysId = -1;
        private ImageView targetImageView;
        private int delayPerFrame = -1;
        private Bitmap lastBitmap = null;
        private int index = -1;
        private int[] drawables = null;
        private Handler handler = null;
        private boolean started = false;
        private Thread gainBitmapThread = null;
    
        public AnimationsContainer(Context context, int arraysId, ImageView targetImageView, int delayPerFrame) {
            this.context = context;
            this.arraysId = arraysId;
            this.targetImageView = targetImageView;
            this.delayPerFrame = delayPerFrame;
            initHandler();
            drawables = getData(this.arraysId);
        }
    
        private void initHandler(a) {
            handler = new Handler(Looper.getMainLooper()) {
                @Override
                public void handleMessage(@NonNull Message msg) { Bitmap bitmap = (Bitmap) msg.obj; targetImageView.setImageBitmap(bitmap); recycleCurrBitmap(); lastBitmap = bitmap; }}; }private void recycleCurrBitmap(a) {
            if(lastBitmap ! =null) {
                lastBitmap.recycle();
                lastBitmap = null; }}private int getNextIndex(a) {
            int result = index;
            if (result < 0) {
                result = 0;
            } else {
                result = (result + 1) % drawables.length;
            }
            return result;
        }
    
        private Bitmap gainSpecificSizeBitmap(int index) {
            Bitmap bitmap = null;
            bitmap = BitmapFactory.decodeResource(context.getResources(), drawables[index]);
            return bitmap;
        }
    
        public void startAnimation(a) {
            started = true;
            if (gainBitmapThread == null) {
                gainBitmapThread = new Thread(new Runnable() {
                    @Override
                    public void run(a) {
                        while (started) {
                            index = getNextIndex();
                            Bitmap bitmap = gainSpecificSizeBitmap(index);
                            Message message = Message.obtain(handler, 0, bitmap);
                            handler.sendMessage(message);
                            try {
                                Thread.sleep(delayPerFrame);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            if (index >= drawables.length - 1) {
                                stopAnimation();
                                break; }}}}); } gainBitmapThread.start(); }public void stopAnimation(a) {
            started = false;
            handler.removeCallbacksAndMessages(null);
            try {
                if(gainBitmapThread ! =null) {
                    gainBitmapThread.stop();
                    gainBitmapThread = null; }}catch (Exception e) {
                gainBitmapThread = null;
            }
            index = -1;
            recycleCurrBitmap();
        }
    
        / * 
             
             
              
              
               @drawable/img0
               
              
               @drawable/img1
               
              
               @drawable/img2
               
              
               @drawable/img3
               
              
               @drawable/img4
               
              
               @drawable/img5
               
              
               @drawable/img6
               
              
               @drawable/img7
               
              
               @drawable/img8
               
              
               @drawable/img9
               
              
               @drawable/img10
               
              
               @drawable/img11
               
              
               @drawable/img12
               
              
               @drawable/img13
               
              
               @drawable/img14
               
              
               @drawable/img15
               
              
               @drawable/img16
               
              
               @drawable/img17
               
              
               @drawable/img18
               
              
               @drawable/img19
               
              
               @drawable/img20
               
              
               @drawable/img21
               
              
               @drawable/img22
               
              
               @drawable/img23
               
              
               @drawable/img24
               
              
             */
    
        /** * Reads the frame array from XML **@param resId
         * @return* /
        private int[] getData(int resId) {
            TypedArray array = context.getResources().obtainTypedArray(resId);
            int len = array.length();
            int[] intArray = new int[array.length()];
    
            for (int i = 0; i < len; i++) {
                intArray[i] = array.getResourceId(i, 0);
            }
            array.recycle();
            returnintArray; }}// How to use it
    AnimationsContainer controller = new AnimationsContainer(this,R.array.loading_anim,imageView,20);
    controller.startAnimation();
    Copy the code
3. Property animation
  1. Property animation did not find the exact definition. Own understanding:
    • A property animation defines a change to a property P of the specified type
    • Attribute P can belong to an object or exist independently of the object
      • A change to property P of the specified type belonging to an object: ObjectAnimator
      • Change of property P of the specified type out of the concrete object: ValueAnimator
  2. Property animations are classified according to usage scenarios
    • ViewPropertyAnimator
    • ObjectAnimator
    • ValueAnimator
  3. ViewPropertyAnimator animates properties specifically for views. The properties that can be manipulated are specified and limited, but very easy to use.
    View target = **;
    tareget.animate().scaleX(1.50 F).alpha(0.70 F);
    Copy the code
  4. ObjectAnimator
    • ObjectAnimator usage
      CustomView cv = **;
      ObjectAnimator anim = ObjectAnimator.ofFloat(cv,"prop1".1.0 F.2.0 F);
      anim.start();
      
      public class CustomView extends View{
          // The field is 'prop2'
          public String prop2 = null;
          // the method is 'Prop1'
          public void setProp1(String prop){
              this.prop2 = prop;
              invalidate();
          }
          public void getProp1(a){
              return this.prop2;
          }
          ***
      }
      Copy the code
    • You can see the ObjectAnimator feature from the example above
      • Target for a specific object
      • PropertyName in objectAnimator. of** does not need to be a field of target. So long as there’s a setter and getter for the propertyName.
    • Use Keyframe, PropertyValuesHolder can achieve ‘animation to complex attribute the relation’
      • Keyframe is used to divide an attribute into multiple segments for fine control
      • 1 PropertyValuesHolder controls 1 property. Use multiple PropertyValuesHolders to create ObjectAnimator instances. Animate multiple properties simultaneously
        public class CustomView extends View{
            public float a1 = 0.0 F;
            public float a2 = 0.0 F;
            public float a3 = 0.0 F;
            //a1,a2,a3 setter and getter methods
            // Setter methods trigger the redraw /invalidate of the CustomView instance
        }
        
        CustomView cv = ***;
        Keyframe kf1 = Keyframe.ofFloat(0.0 F.0.0 F);
        Keyframe kf2 = Keyframe.ofFloat(0.5 F.120.0 F);
        Keyframe kf2 = Keyframe.ofFloat(10.10.0 F);
        PropertyValuesHolder holder1= PropertyValuesHolder.ofKeyframe("a1", kf1, kf2, kf3);
        ***
        PropertyValuesHolder holder2= PropertyValuesHolder.ofKeyframe("a2", kf4, kf5, kf6);
        ***
        PropertyValuesHolder holder3= PropertyValuesHolder.ofKeyframe("a3", kf7, kf8, kf9);
        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(cv, holder1,holder2,holder3);
        animator.start();
        Copy the code
  5. ValueAnimator
    • ValueAnimator is the parent of ObjectAnimator.
    • ValueAnimator is used to declare a change to an attribute of the specified type that is independent of the object.
    • ValueAnimator, because it is not associated with a specific instance, needs to fetch the current property value in the animation listener callback and execute specific logic, which is slightly more cumbersome than ObjectAnimator, but also less restrictive and more applicable.
    • ValueAnimator Usage scenarios:
      • In short, scenarios that ObjectAnimator cannot implement are handed over to ValueAnimator. For example, a field in a third-party library, no setter methods, or you want to use an animation to control property changes on multiple objects, etc.

N

  • The Art of Android Development (Book)
  • Property animation Overview
  • Android animation system details
  • Android must know must know — animation
  • Android Skill Tree – Animation summary
  • Android Animation: This is a detailed and clear animation learning guide
  • Making custom LayoutAnimationController
  • HenCoder Android custom View 1-6: Property Animation
  • HenCoder Android custom View 1-7: Property Animation