TransformationLayout
🌠 Transform between two Views, Activities, and Fragments, or a View to a Fragment with container transform animations for Android.
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
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
- 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()
- 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)
- Customizing animation parameters:
transformationLayout.apply {
duration = 500
pathMotion = ArcMotion()
interpolator = AccelerateDecelerateInterpolator()
}
Getting Started
- Add the dependency to your app's
build.gradle
:
dependencies {
implementation "com.github.skydoves:transformationlayout: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>
- 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.
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 designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
TransformationLayout
ð Transform views, activity, and fragments into other components with container transform animations.
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
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
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. |
allContainerColor | Color | Color.TRANSPARENT | The all container colors (start and end) 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. |
startElevation | Float | ELEVATION_NOT_SET | The elevation that will be used to render a shadow around the container at the start of the transition. |
endElevation | Float | ELEVATION_NOT_SET | The elevation that will be used to render a shadow around the container at the end of the transition. |
elevationShadowEnabled | Boolean | true if (version > Pie) | Whether shadows should be drawn around the container to approximate native elevation shadows on the start and end views. |
holdAtEndEnabled | Boolean | false | Whether 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.
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.
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
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.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot