Check and cross animation with vector drawable and path commands

The following are steps for creating a check/tick and cross animation using vector drawable and path commands. The animation of the check and cross can be used for success or failure scenarios.

Create a vector drawable for drawing the check, vector_path_check.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportHeight="24.0"
    android:viewportWidth="24.0">
  <group android:name="check">
    <path
        android:name="check_path"
        android:pathData="M6,10 l0,0 l0,0"
        android:strokeColor="#48f242"
        android:strokeWidth="2" />
  </group>
</vector>

Create a vector drawable for drawing the cross, vector_path_cross.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportHeight="24.0"
    android:viewportWidth="24.0">
  <group android:name="cross">
    <path
        android:name="cross_path"
        android:pathData="M6,6 l0,0 M16,6 l0,0"
        android:strokeColor="#f10b59"
        android:strokeWidth="2" />
  </group>
</vector>

Create a animated-vector drawable for animating the check, animated_vector_check.xml

<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:aapt="http://schemas.android.com/aapt"
  android:drawable="@drawable/vector_path_check">
  <!--<target-->
  <!--android:name="check_path"-->
  <!--android:animation="@anim/check_animation" />-->

  <target android:name="check_path">
    <aapt:attr name="android:animation">
      <set
          android:interpolator="@android:anim/accelerate_interpolator"
          android:ordering="sequentially"
          android:shareInterpolator="false">
        <!-- First animation, the short backward slash part of the check, \ -->
        <objectAnimator
            android:duration="@android:integer/config_shortAnimTime"
            android:propertyName="pathData"
            android:valueFrom="M6,10 l0,0 l0,0"
            android:valueTo="M6,10 l4,4.5 l0,0"
            android:valueType="pathType" />
        
        <!-- Second animation, the long forward slash part of the check, / -->
        <objectAnimator
            android:duration="@android:integer/config_shortAnimTime"
            android:propertyName="pathData"
            android:valueFrom="M6,10 l4,4.5 l0,0"
            android:valueTo="M6,10 l4,4.5 l9,-8"
            android:valueType="pathType" />
      </set>
    </aapt:attr>
</target>

</animated-vector>

Create a animated-vector drawable for animating the cross, animated_vector_cross.xml

<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:aapt="http://schemas.android.com/aapt"
  android:drawable="@drawable/vector_path_cross">
  <target android:name="cross_path">
    <aapt:attr name="android:animation">
      <set
          android:interpolator="@android:anim/accelerate_interpolator"
          android:ordering="sequentially"
          android:shareInterpolator="false">
        <!-- First animation, the first stroke from top left to bottom right \ -->
        <objectAnimator
            android:duration="@android:integer/config_shortAnimTime"
            android:propertyName="pathData"
            android:valueFrom="M6,6 l0,0 M16,6 l0,0"
            android:valueTo="M6,6 l10,10 M16,6 l0,0"
            android:valueType="pathType" />
        
        <!-- Second animation, the second strok from top right to bottom left / -->
        <objectAnimator
            android:duration="@android:integer/config_shortAnimTime"
            android:propertyName="pathData"
            android:valueFrom="M6,6 l10,10 M16,6 l0,0"
            android:valueTo="M6,6 l10,10 M16,6 l-10,10"
            android:valueType="pathType" />
      </set>
    </aapt:attr>
</target>

</animated-vector>

Using the above vector drawable and animated-vector drawable. The layout file activity_main.xml

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rootview"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true">

        <ImageView
            android:id="@+id/check"
            android:layout_width="128dp"
            android:layout_height="128dp"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:contentDescription="@null"
            android:padding="8dp"
            android:scaleType="fitXY"
            android:src="@drawable/animated_vector_check"/>

        <ImageView
            android:id="@+id/cross"
            android:layout_width="128dp"
            android:layout_height="128dp"
            android:layout_alignTop="@id/check"
            android:layout_toEndOf="@id/check"
            android:contentDescription="@null"
            android:padding="8dp"
            android:scaleType="fitXY"
            android:src="@drawable/animated_vector_cross"/>
    </RelativeLayout>
</RelativeLayout>

The MainActivity.java

import android.graphics.drawable.Animatable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {

    private ImageView checkView;
    private ImageView crossView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        checkView = (ImageView) findViewById(R.id.check);
        crossView = (ImageView) findViewById(R.id.cross);


        checkView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ((Animatable) checkView.getDrawable()).start();
            }
        });

        crossView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ((Animatable) crossView.getDrawable()).start();
            }
        });
    }

}

This vector command means starting at point 6,10 then draw a line to the point which is obtained by increase x by 4 and y by 4.5, and the thrid command l0,0 means stay at the current position.

M6,10 l4,4.5 l0,0

This vector command, the frist two commands M6,10 l4,4.5 is the same as the above, the third means draw line to the point which is obtained by increase x by 9 and decrease y by -8

M6,10 l4,4.5 l9,-8

Android Path command basics

  • In a 24 by 24 space, the origin 0,0 is at the top left corner, going right will increase the x value, going down will increase the y value.
  • Mx,y means start at x,y
  • lx,y means draw a line from the current coordinate to the position specified by x,y
  • The lower case lx,y means move from the current coordinate by x and y and draw the line
  • The upper case Lx,y means move from the origin 0,0
  • C x1,y1 x2,y2 x,y means draw a cubic bezier curve to (x,y) using control points (x1,y1) and (x2,y2)
  • Z Close the path by drawing a line back to the beginning of the current subpath.

Complete example in Github
Reference:
https://medium.com/@ali.muzaffar/understanding-vectordrawable-pathdata-commands-in-android-d56a6054610e
http://www.androiddesignpatterns.com/2016/11/introduction-to-icon-animation-techniques.html#drawing-paths

Search within Codexpedia

Custom Search

Search the entire web

Custom Search