TransformationLayout

Transform into a different view or activity using morphing animations.
Using Transformation motions of new material version.
preview0

preview1

preview2

Including in your project

Download
JitPack

Gradle

Add below codes to your root build.gradle file (not your module build.gradle file).

allprojects {
    repositories {
        jcenter()
    }
}

And add a dependency code to your module's build.gradle file.

dependencies {
    implementation "com.github.skydoves:transformationlayout:1.0.1"
}

Usage

Add following XML namespace inside your XML layout file.

xmlns:app="http://schemas.android.com/apk/res-auto"

TransformationLayout

Here is a basic example of implementing TransformationLayout.

We must wrap one or more views that we want to transform.

<com.skydoves.transformationlayout.TransformationLayout
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:transformation_targetView="@+id/my_cardView" // sets a target view.
  app:transformation_duration="450" // sets a duration of the transformation.
  app:transformation_direction="auto" // auto, entering, returning
  app:transformation_fadeMode="in" // in, out, cross, through
  app:transformation_fitMode="auto" // auto, height, width
  app:transformation_pathMode="arc" // arc, linear
>

   <!-- other views -->

</com.skydoves.transformationlayout.TransformationLayout>

Transform into a view

Here is a simple example of transform fab into a view.

<com.skydoves.transformationlayout.TransformationLayout
    android:id="@+id/transformationLayout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:transformation_duration="550"
    app:transformation_targetView="@+id/myCardView">

  <com.google.android.material.floatingactionbutton.FloatingActionButton
      android:id="@+id/fab"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:backgroundTint="@color/colorPrimary"
      android:src="@drawable/ic_write"/>
</com.skydoves.transformationlayout.TransformationLayout>

<com.google.android.material.card.MaterialCardView
    android:id="@+id/myCardView"
    android:layout_width="240dp"
    android:layout_height="312dp"
    android:layout_marginLeft="30dp"
    android:layout_marginTop="30dp"
    app:cardBackgroundColor="@color/colorPrimary" />

Bind a TargetView

We can bind a targetView that will be transformed from the TransformationLayout using the below attribute in XML.

If you bind a targetView to the TransformationLayout, the targetView's visibility will be GONE.

app:transformation_targetView="@+id/myCardView"

Or we can bind a targetView using method.

transformationLayout.bindTargetView(myCardView)

Starting and finishing the transformation

After binding a targetView, we can start or finish transformation using the below methods.

The startTransform and finishTransform methods need a parent as a parameter.

The parent parameter should be the root layout (the highest level layout).

// start transformation when touching the fab.
fab.setOnClickListener {
  transformationLayout.startTransform(parent)
}

// finish transformation when touching the myCardView.
myCardView.setOnClickListener {
  transformationLayout.finishTransform(parent)
}

Transform into an Activity

Here is an example of a transforming floating action button to Activity.

We don't need to bind a targetView.

<com.skydoves.transformationlayout.TransformationLayout
    android:id="@+id/transformationLayout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:transformation_duration="550">

  <com.google.android.material.floatingactionbutton.FloatingActionButton
      android:id="@+id/fab"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:backgroundTint="@color/colorPrimary"
      android:src="@drawable/ic_write"/>
</com.skydoves.transformationlayout.TransformationLayout>

onTransformationStartContainer

We should add onTransformationStartContainer() to the Activity that has the floating action button. If your view is in the fragment, the code should be added to the fragment's Activity. It must be called before super.onCreate.

override fun onCreate(savedInstanceState: Bundle?) {
    onTransformationStartContainer() // should be called before super.onCreate().
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
}

Here is the Java way.

TransitionExtensionKt.onTransformationStartContainer(this);

startActivity

And we should call startActivity with bundle and intent data.

We should get a bundle using withActivity method. It needs a context and any name of transition.

The bundle must be used as startActivity's parameter.

We should put parcelable data to the intent using getParcelableParams() method.

The extra name of the parcelable data can be anything, and it will be reused later.

fab.setOnClickListener {
    val bundle = transformationLayout.withActivity(this, "myTransitionName")
    val intent = Intent(this, DetailActivity::class.java)
    intent.putExtra("TransformationParams", transformationLayout.getParcelableParams())
    startActivity(intent, bundle)
}

If we want to get bundle data in RecyclerView or other classes,

we can use withView and withContext instead of withActivty.

// usage in the RecyclerView.Adapter
override fun onBindViewHolder(holder: PosterViewHolder, position: Int) {
   val bundle = transformationLayout.withView(holder.itemView, "myTransitionName")
}

Here is the Java way.

Bundle bundle = transformationLayout.withActivity(this, "myTransitionName");
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("TransformationParams", transformationLayout.getParcelableParams());
startActivity(intent, bundle);

onTransformationEndContainer

And finally, we should add onTransformationEndContainer() to the Activity that will be started.

It must be added before super.onCreate.

override fun onCreate(savedInstanceState: Bundle?) {
    onTransformationEndContainer(intent.getParcelableExtra("TransformationParams"))
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_detail)
}

Here is the Java way.

TransformationLayout.Params params = getIntent().getParcelableExtra("myTransitionName");
TransitionExtensionKt.onTransformationEndContainer(this, params);

OnTransformFinishListener

We can listen a TransformationLayout is transformed or not using OnTransformFinishListener.

transformationLayout.setOnTransformFinishListener {
  Toast.makeText(context, "is transformed: $it", Toast.LENGTH_SHORT).show()
}

Here is the Java way.

transformationLayout.onTransformFinishListener = new OnTransformFinishListener() {
  @Override public void onFinish(boolean isTransformed) {
    Toast.makeText(context, "is transformed:" + isTransformed, Toast.LENGTH_SHORT).show();
  }
};

TransformationLayout Attributes

Attributes Type Default Description
targetView resource id none Bind a targetView that will be transformed.
duration Long 350L Duration of the transformation.
pathMotion Motion.ARC, Motion.LINEAR default layout Indicates that this transition should be drawn as the which path.
containerColor Color Color.TRANSPARENT Set the container color to be used as the background of the morphing container.
scrimColor Color Color.TRANSPARENT Set the color to be drawn under the morphing container.
direction Direction.AUTO, Direction.ENTER, Direction.RETURN Direction.AUTO Set the direction to be used by this transform.
fadeMode FadeMode.IN, FadeMode.OUT, FadeMode.CROSS, FadeMode.THROUGH FadeMode.IN Set the FadeMode to be used to swap the content of the start View with that of the end View.
fitMode FitMode.AUTO, FitMode.WIDTH, FitMode.HEIGHT FitMode.AUTO Set the fitMode to be used when scaling the incoming content of the end View.

Find this library useful? :heart:

Support it by joining stargazers for this repository.

GitHub