ConstraintLayout is similar to RelativeLayout and provides more flexibility than RelativeLayout. Views are placed with a relationship with each other furthermore Android Studio layout editor provides advanced editing controls. Android application having animations gives a very good user experience. Creating animations in Android is simple but still takes lots of efforts for complex animations. With ConstraintLayout we can create complex animations with fewer efforts. This tutorial will a demonstration of Keyframe Animations with ConstraintLayout and ConstraintSet.
DOWNLOAD SOURCE CODE OR APK
DEMO
Keyframe Animations with ConstraintLayout and ConstraintSet Example.

Adding ConstraintLayout Library to your project
STEP 1: Create or open an existing Android Studio project. Open build.gradle of project module and add the following lines to it.
repositories {
maven {
url 'https://maven.google.com'
}
}
STEP 2: Open app level build.gradle modify it and add a dependency for ConstraintLayout as given below.
dependencies {
/*Add constraint layout dependency*/
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
/*Add cardview dependency for designing layout with cards*/
implementation 'com.android.support:cardview-v7:27.0.2'
}
STEP 3: Download this images and add it to res -> drawable folder
STEP 4: Create new layout inside res -> layout -> key_frame_default.xml. This layout is the first frame of animation. Bind all the data and positioning information in this view as shown below.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/constrainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center">
<android.support.v7.widget.CardView
android:id="@+id/carViewOne"
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/carViewTwo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageViewOne"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/textViewOne"
android:scaleType="centerCrop"
android:src="@drawable/fruit_one" />
<TextView
android:id="@+id/textViewOne"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:text="Card One"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
</RelativeLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/carViewTwo"
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/carViewOne"
app:layout_constraintTop_toTopOf="parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:src="@drawable/fruit_two"
android:scaleType="centerCrop"
android:id="@+id/imageViewTwo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/textViewTwo" />
<TextView
android:id="@+id/textViewTwo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:text="Card Two"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</android.support.constraint.ConstraintLayout>
STEP 5: Now create new layout res -> layout -> key_frame_one.xml. This layout will contain only positioning information.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center">
<android.support.v7.widget.CardView
android:id="@+id/carViewOne"
android:layout_width="180dp"
android:layout_height="200dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageViewOne"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/textViewOne" />
<TextView
android:id="@+id/textViewOne"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:text="Card One"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
</RelativeLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/carViewTwo"
android:layout_width="180dp"
android:layout_height="200dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/carViewOne">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageViewTwo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/textViewTwo" />
<TextView
android:id="@+id/textViewTwo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:text="Card Two"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</android.support.constraint.ConstraintLayout>
STEP 6: Now we will create a new activity. So create new layout res -> layout -> content_main.xml. Add the following lines to it. The layout will contain two buttons at the bottom. defaultKeyFrameButton is for moving layout to the default position. KeyFrameOneButton will move default layouts child’s positions to as defined in key_frame_one.xml layout with animation.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<!--include default key frame in activity layout-->
<include layout="@layout/key_frame_default" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:weightSum="2">
<Button
android:id="@+id/defaultKeyFrameButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Move to Default" />
<Button
android:id="@+id/KeyFrameOneButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Move to KeyFrameOne" />
</LinearLayout>
</RelativeLayout>
STEP 7: Create new layout res -> layout -> activity_main.xml. add following lines to it.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_main" />
</android.support.design.widget.CoordinatorLayout>
STEP 8: Create new class package name -> MainActivity.java. Add following code to it.
import android.os.Bundle;
import android.support.constraint.ConstraintLayout;
import android.support.constraint.ConstraintSet;
import android.support.transition.TransitionManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Bind constrainLayout
final ConstraintLayout constrainLayout = findViewById(R.id.constrainLayout);
//Bind buttons
Button defaultKeyFrameButton = findViewById(R.id.defaultKeyFrameButton);
Button KeyFrameOneButton = findViewById(R.id.KeyFrameOneButton);
defaultKeyFrameButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//defaultKeyFrameButton clicked create new ConstraintSet
ConstraintSet constraintSet = new ConstraintSet();
//Clone positioning information from @key_frame_default.xml in ConstraintSet
constraintSet.clone(MainActivity.this, R.layout.key_frame_default);
//beginDelayedTransition is Convenience method to animate to a new
// scene defined by all changes within
// the given scene root between calling
// this method and the next rendering frame.
TransitionManager.beginDelayedTransition(constrainLayout);
//Then apply ConstraintSet to ConstraintLayout
//this will move views with animation to positions
//as defined in key_frame_default.xml layout
constraintSet.applyTo(constrainLayout);
}
});
KeyFrameOneButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//KeyFrameOneButton clicked create new ConstraintSet
ConstraintSet constraintSet = new ConstraintSet();
//Clone positioning information from @key_frame_one.xml in ConstraintSet
constraintSet.clone(MainActivity.this, R.layout.key_frame_one);
//beginDelayedTransition is Convenience method to animate to a new
// scene defined by all changes within
// the given scene root between calling
// this method and the next rendering frame.
TransitionManager.beginDelayedTransition(constrainLayout);
//Then apply ConstraintSet to ConstraintLayout
//this will move views with animation to positions
//as defined in key_frame_one.xml layout
constraintSet.applyTo(constrainLayout);
}
});
}
}
TransitionManager.beginDelayedTransition():
beginDelayedTransition is a Convenience method to animate to a new scene defined by all changes within the given scene root between calling this method and the next rendering frame.
constraintSet.clone(activity,layout):
This method will clone all the positioning information from the layout and will store in constraints object.
STEP 9: Mention this activity in manifest.xml to as shown below.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.loopwiki.constrinlayoutandroidexample">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
STEP 10: Run the application.

If you still have any queries, please post them in the comments section below, I will be happy to help you.