Convert Figma logo to code with AI

skydoves logoTransformationLayout

🌠 Transform between two Views, Activities, and Fragments, or a View to a Fragment with container transform animations for Android.

2,349
190
2,349
7

Top Related Projects

Modular and customizable Material Design UI components for Android

Render After Effects animations natively on Android and iOS, Web, and React Native

5,436

A Java library that models spring dynamics and adds real world physics to your app.

An Android Animation library which easily add itemanimator to RecyclerView items.

A fluent Android animation library

Cute view animation collection.

Quick Overview

TransformationLayout is an Android library that provides smooth transformation animations between views or activities. It allows developers to create seamless transitions between UI elements, enhancing the user experience with fluid and visually appealing animations.

Pros

  • Easy to implement with minimal code changes
  • Supports both view-to-view and activity-to-activity transformations
  • Customizable animation parameters (duration, interpolator, etc.)
  • Compatible with various Android UI components and layouts

Cons

  • May introduce additional complexity for simple UI transitions
  • Potential performance impact on older devices with complex animations
  • Limited to specific transition types (e.g., expand/collapse)
  • Requires careful implementation to avoid visual glitches

Code Examples

  1. Basic view-to-view transformation:
// In the source view's click listener
transformationLayout.startTransform()

// In the target view's onAttach or similar lifecycle method
transformationLayout.finishTransform()
  1. Activity-to-activity transformation:
// In the source activity
val intent = Intent(this, TargetActivity::class.java)
TransformationCompat.startActivity(transformationLayout, intent)

// In the target activity's onCreate
TransformationCompat.onTransformationEndContainer(this)
  1. Customizing animation parameters:
transformationLayout.apply {
    duration = 500
    pathMotion = ArcMotion()
    interpolator = AccelerateDecelerateInterpolator()
}

Getting Started

  1. Add the dependency to your app's build.gradle:
dependencies {
    implementation "com.github.skydoves:transformationlayout:1.1.1"
}
  1. Wrap your source view with TransformationLayout in XML:
<com.skydoves.transformationlayout.TransformationLayout
    android:id="@+id/transformationLayout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    
    <!-- Your source view here -->

</com.skydoves.transformationlayout.TransformationLayout>
  1. Implement the transformation in your Kotlin code as shown in the code examples above.

Competitor Comparisons

Modular and customizable Material Design UI components for Android

Pros of material-components-android

  • Comprehensive library with a wide range of Material Design components
  • Official Google implementation, ensuring consistency with Material Design guidelines
  • Regular updates and extensive documentation

Cons of material-components-android

  • Larger library size, potentially increasing app size
  • Less focused on specific transition animations compared to TransformationLayout
  • May require more setup and configuration for custom transitions

Code Comparison

TransformationLayout:

transformationLayout.startTransform(targetView)

material-components-android:

val transition = MaterialContainerTransform()
TransitionManager.beginDelayedTransition(container, transition)

Key Differences

  • TransformationLayout focuses specifically on view transformations and animations
  • material-components-android provides a broader set of UI components and design elements
  • TransformationLayout offers simpler implementation for specific transition effects
  • material-components-android integrates more seamlessly with other Material Design components

Use Cases

  • Choose TransformationLayout for quick and easy implementation of specific view transformations
  • Opt for material-components-android when building a comprehensive Material Design-based app with various UI components

Render After Effects animations natively on Android and iOS, Web, and React Native

Pros of Lottie-Android

  • Supports complex animations created in Adobe After Effects
  • Large community and extensive documentation
  • Cross-platform support (iOS, Android, Web)

Cons of Lottie-Android

  • Larger file size and potentially higher memory usage
  • Learning curve for creating custom animations
  • Limited runtime manipulation of animations

Code Comparison

TransformationLayout:

TransformationLayout.bindOnPreDraw(
    previewImageView,
    detailActivityIntent,
    "myTransitionName"
)

Lottie-Android:

val animationView = findViewById<LottieAnimationView>(R.id.animation_view)
animationView.setAnimation(R.raw.animation)
animationView.playAnimation()

Key Differences

TransformationLayout focuses on creating smooth transitions between UI elements, while Lottie-Android specializes in rendering complex vector animations. TransformationLayout is more lightweight and easier to implement for simple transitions, whereas Lottie-Android offers more advanced animation capabilities but with a steeper learning curve.

TransformationLayout is ideal for enhancing UI transitions within an app, while Lottie-Android excels at incorporating high-quality, pre-designed animations into your application. The choice between the two depends on the specific animation needs of your project and the level of complexity you're willing to work with.

5,436

A Java library that models spring dynamics and adds real world physics to your app.

Pros of Rebound

  • More mature and battle-tested library, developed by Facebook
  • Focuses on spring animations, providing a powerful physics-based animation system
  • Can be used for a wide variety of animation scenarios beyond layout transformations

Cons of Rebound

  • Less focused on layout transformations specifically
  • Requires more setup and configuration for complex animations
  • Not actively maintained (archived repository)

Code Comparison

TransformationLayout:

TransformationLayout.bindTargetView(startView, endView)
transformationLayout.startTransform()

Rebound:

Spring spring = springSystem.createSpring();
spring.addListener(new SimpleSpringListener() {
    @Override
    public void onSpringUpdate(Spring spring) {
        float value = (float) spring.getCurrentValue();
        // Update view properties based on spring value
    }
});
spring.setEndValue(1);

Summary

TransformationLayout is a more specialized library for Android layout transformations, offering a simpler API for specific use cases. Rebound, while more versatile and powerful for spring-based animations, requires more setup and is no longer actively maintained. TransformationLayout may be preferable for straightforward layout transitions, while Rebound could be better for complex, physics-based animations across various UI elements.

An Android Animation library which easily add itemanimator to RecyclerView items.

Pros of recyclerview-animators

  • Focuses specifically on RecyclerView animations, offering a wide range of pre-built animations
  • Provides easy-to-use methods for adding, removing, and changing items with animations
  • Supports custom animations for more flexibility

Cons of recyclerview-animators

  • Limited to RecyclerView animations, not applicable for other UI transformations
  • May require additional setup for complex custom animations
  • Less suitable for creating seamless transitions between activities or fragments

Code Comparison

TransformationLayout:

transformationLayout.startTransform()
transformationLayout.finishTransform()

recyclerview-animators:

val animator = SlideInLeftAnimator()
recyclerView.itemAnimator = animator

Summary

TransformationLayout offers a more comprehensive solution for creating seamless transitions between UI elements, including activities and fragments. It provides a flexible approach to transforming views with various animation options.

recyclerview-animators, on the other hand, specializes in RecyclerView animations, offering a wide range of pre-built animations for item additions, removals, and changes. It's an excellent choice for projects that require specific RecyclerView animations but may be less suitable for broader UI transformations.

The choice between these libraries depends on the specific needs of your project. If you're focusing on RecyclerView animations, recyclerview-animators might be more appropriate. For more general UI transformations and seamless transitions, TransformationLayout could be the better option.

A fluent Android animation library

Pros of ViewAnimator

  • Offers a wider range of animation types, including fade, flip, slide, and zoom
  • Provides chaining of multiple animations for complex effects
  • Supports both Java and Kotlin

Cons of ViewAnimator

  • Less focused on layout transformations compared to TransformationLayout
  • May require more code to achieve similar layout transition effects
  • Lacks specific features for seamless activity/fragment transitions

Code Comparison

ViewAnimator:

ViewAnimator
    .animate(targetView)
    .scale(0f, 1f)
    .duration(1000)
    .start()

TransformationLayout:

transformationLayout.startTransform()
// ... perform layout changes
transformationLayout.finishTransform()

Key Differences

  • TransformationLayout specializes in smooth transitions between different layouts and activities
  • ViewAnimator focuses on general-purpose view animations within a single layout
  • TransformationLayout offers a more declarative API for complex layout transformations
  • ViewAnimator provides more flexibility for creating custom animation sequences

Both libraries have their strengths, with TransformationLayout excelling in layout transitions and ViewAnimator offering a broader range of animation options for individual views.

Cute view animation collection.

Pros of AndroidViewAnimations

  • Extensive collection of pre-built animations
  • Simple API for applying animations to views
  • Supports chaining multiple animations

Cons of AndroidViewAnimations

  • Limited to view-level animations
  • Less flexibility for complex, custom transitions
  • Not optimized for material design transitions

Code Comparison

AndroidViewAnimations:

YoYo.with(Techniques.FadeIn)
    .duration(1000)
    .playOn(view)

TransformationLayout:

transformationLayout.startTransform(targetView)

Key Differences

TransformationLayout focuses on seamless transitions between activities or fragments, ideal for material design implementations. It excels in creating smooth, morphing animations between different UI states.

AndroidViewAnimations provides a wide array of simple, ready-to-use animations for individual views. It's better suited for adding quick, eye-catching effects to elements within a single screen.

While TransformationLayout offers more complex and customizable transitions, AndroidViewAnimations is easier to implement for basic animation needs.

TransformationLayout is more modern and aligned with current Android design principles, whereas AndroidViewAnimations has been around longer and has a larger user base.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

TransformationLayout


🌠 Transform views, activity, and fragments into other components with container transform animations.


Google License API Build Status Profile

Download

Go to the Releases to download the demo APK.

Screenshots

Morphing Animation for Jetpack Compose

If you want to implement morphing animation in Jetpack Compose, check out Orbital.

Including in your project

Maven Central

Gradle

Add the dependency below to your module's build.gradle file:

dependencies {
    implementation("com.github.skydoves:transformationlayout:1.1.4")
}

Usage

Add the XML namespace below inside your XML layout file:

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

TransformationLayout

TransformationLayout is an essential concept to transform your Views, Activities, and Fragments into other components. You must wrap one or more Views that are supposed to be transformed using TransformationLayout like the example code below:

<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 complicated views -->

</com.skydoves.transformationlayout.TransformationLayout>

Transform into a view

For instance, you can transform a floating button into a CardView as you've seen in the example below:

<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

With the attribute below in your XML file, you can bind a targetView that should be transformed from the TransformationLayout. If you bind a targetView with a TransformationLayout, the targetView's visibility will be GONE by default.

app:transformation_targetView="@+id/myCardView"

You can also bind a targetView with a TransformationLayout using bindTargetView method like the code below:

transformationLayout.bindTargetView(myCardView)

Starting and finishing the transformation

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

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

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

Here are other functionalities to starting and finishing transformation.

// starts and finishes transformation 1000 milliseconds later.
// If we use this method on onCreate() method, it will starts transformation automatically 200ms later.
transformationLayout.startTransformWithDelay(200)
transformationLayout.finishTransformWithDelay(200)

// starts and finishes transformation with stopping a parent layout.
transformationLayout.startTransform(parent)
transformationLayout.finishTransform(parent)

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();
  }
};

Transform into an Activity

We can implement transformation between activities easily using TransformationActivity and TransformationCompat.

Here is an example of transforming a 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.

TransformationCompat.onTransformationStartContainer(this);

TransformationAppCompatActivity

Extends TransformationAppCompatActivity or TransformationActivity to your activity that will be transformed.

class DetailActivity : TransformationAppCompatActivity()

Here is the Java way.

public class DetailActivity extends TransformationAppCompatActivity 

TransformationCompat

And start the DetailActivity using the TransformationCompat.startActivity method.

val intent = Intent(context, DetailActivity::class.java)
TransformationCompat.startActivity(transformationLayout, intent)

Here is the Java way.

Intent intent = new Intent(context, DetailActivity.class);
TransformationCompat.startActivity(transformationLayout, intent);

Manually Transform into an Activity

Here is an example of transforming a 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.

TransformationCompat.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("TransformationParams");
TransformationCompat.onTransformationEndContainer(this, params);

Transform into a Fragment

We can implement transformation between fragments for a single Activity application.
Here is an example of transforming a floating action button in Fragment A to Fragment B.

<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 call onTransformationStartContainer() in the Fragment A that has the floating action button.

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  onTransformationStartContainer()
}

Here is the Java way.

TransformationCompat.onTransformationStartContainer(this);

getBundle and addTransformation

We should get a bundle from the TransformationLayout and put it into the argument.
And in the fragment manager's transaction, we should add the TransformationLayout using addTransformation method.

val fragment = MainSingleDetailFragment()
val bundle = transformationLayout.getBundle("TransformationParams")
bundle.putParcelable(MainSingleDetailFragment.posterKey, poster)
fragment.arguments = bundle

requireFragmentManager()
  .beginTransaction()
  .addTransformation(transformationLayout)
  .replace(R.id.main_container, fragment, MainSingleDetailFragment.TAG)
  .addToBackStack(MainSingleDetailFragment.TAG)
  .commit()
}

Here is the Java way

MainSingleDetailFragment fragment = new MainSingleDetailFragment();
Bundle bundle = transformationLayout.getBundle("TransformationParams", "transitionName");
fragment.setArguments(bundle);

FragmentTransaction fragmentTransaction = requireFragmentManager().beginTransaction();
TransformationCompat.addTransformation(
    fragmentTransaction, transformationLayout, "transitionName");
fragmentTransaction.replace(R.id.main_container, fragment, MainSingleDetailFragment.TAG)
    .addToBackStack(MainSingleDetailFragment.TAG)
    .commit();

Transition name in Fragment A

We must set a specific transition name to the TransformationLayout.
If you want to transform a recyclerView's item, set transiton name in onBindViewHolder.

transformationLayout.transitionName = "myTransitionName"

Here is the Java way.

transformationLayout.setTransitionName("myTransitionName");

onTransformationEndContainer in Fragment B

We should get a TransformationLayout.Params from the arguments, and call onTransformationEndContainer method.
It must be called in onCreate method.

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)

  val params = arguments?.getParcelable<TransformationLayout.Params>("TransformationParams")
  onTransformationEndContainer(params)
}

Here is the Java way.

TransformationLayout.Params params = getArguments().getParcelable("TransformationParams");
TransformationCompat.onTransformationEndContainer(this, params);

Transition name in Fragment B

And finally set the specific transition name (same as the transformationLayot in Fragment A)
to the target view in Fragment B in onViewCreated.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  super.onViewCreated(view, savedInstanceState)
   
  detail_container.transitionName = "myTransitionName"
}

TransformationLayout Attributes

AttributesTypeDefaultDescription
targetViewresource idnoneBind a targetView that will be transformed.
durationLong350LDuration of the transformation.
pathMotionMotion.ARC, Motion.LINEARdefault layoutIndicates that this transition should be drawn as the which path.
containerColorColorColor.TRANSPARENTSet the container color to be used as the background of the morphing container.
allContainerColorColorColor.TRANSPARENTThe all container colors (start and end) to be used as the background of the morphing container.
scrimColorColorColor.TRANSPARENTSet the color to be drawn under the morphing container.
directionDirection.AUTO, Direction.ENTER, Direction.RETURNDirection.AUTOSet the direction to be used by this transform.
fadeModeFadeMode.IN, FadeMode.OUT, FadeMode.CROSS, FadeMode.THROUGHFadeMode.INSet the FadeMode to be used to swap the content of the start View with that of the end View.
fitModeFitMode.AUTO, FitMode.WIDTH, FitMode.HEIGHTFitMode.AUTOSet the fitMode to be used when scaling the incoming content of the end View.
startElevationFloatELEVATION_NOT_SETThe elevation that will be used to render a shadow around the container at the start of the transition.
endElevationFloatELEVATION_NOT_SETThe elevation that will be used to render a shadow around the container at the end of the transition.
elevationShadowEnabledBooleantrue if (version > Pie)Whether shadows should be drawn around the container to approximate native elevation shadows on the start and end views.
holdAtEndEnabledBooleanfalseWhether to hold the last frame at the end of the animation.

Additional 🎈

You can reference the usage of the TransformationLayout in another repository MarvelHeroes.
A demo application based on modern Android application tech-stacks and MVVM architecture.

screenshot

Find this library useful? :heart:

Support it by joining stargazers for this repository. :star:
And follow me for my next creations! 🤩

License

Copyright 2020 skydoves (Jaewoong Eum)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.