Home > Enterprise >  Animate inner views in MotionLayout
Animate inner views in MotionLayout

Time:10-28

I was able to animate views that are within MotionLayout but couldn't animate views that are inside another view that is inside MotionLayout.

<androidx.constraintlayout.motion.widget.MotionLayout
...
    <com.google.android.material.card.MaterialCardView
     ...
       <androidx.constraintlayout.widget.ConstraintLayout

<!-- I need to animate views that are here when the RecyclerView is scrolling -->
        ...
       </androidx.constraintlayout.widget.ConstraintLayout>
     </com.google.android.material.card.MaterialCardView>

<TextView/>
<androidx.recyclerview.widget.RecyclerView/>
</androidx.constraintlayout.motion.widget.MotionLayout>

Is there a way to animate the views that are inside the MaterialCardView when scrolling the RecyclerView?

enter image description here

CodePudding user response:

MotionLayout can only animate its children.

There are two ways that you might do this..

  1. Flatten the layout to something like this:
<androidx.constraintlayout.motion.widget.MotionLayout
   ...
   <com.google.android.material.card.MaterialCardView
   </com.google.android.material.card.MaterialCardView> 
   <!-- I need to animate views that are here -->
        ...
   <TextView/>
   <androidx.recyclerview.widget.RecyclerView/>
</androidx.constraintlayout.motion.widget.MotionLayout>

The card view will below the widgets and you can constrain to the CardView as you would the ConstraintLayout (where you used parent) This would also be more performant.

  1. You can not use MotionLayout track the scroll and implement your own transition.

  2. You can use code to listen to the progress of of the MotionLayout and drive the views directly

CodePudding user response:

Manage motion and widget animation with MotionLayout

MotionLayout is a layout type that helps you manage motion and widget animation in your app. MotionLayout is a subclass of ConstraintLayout and builds upon its rich layout capabilities. As part of the ConstraintLayout library, MotionLayout is available as a support library and is backwards-compatible to API level 14.

enter image description here

Figure 1. Basic touch-controlled motion. MotionLayout bridges the gap between layout transitions and complex motion handling, offering a mix of features between the property animation framework, TransitionManager, and CoordinatorLayout.

In addition to describing transitions between layouts, MotionLayout lets you animate any layout properties, as well. Moreover, it inherently supports seekable transitions. This means that you can instantly show any point within the transition based on some condition, such as touch input. MotionLayout also supports keyframes, enabling fully customized transitions to suit your needs.

MotionLayout is fully declarative, meaning that you can describe any transitions in XML, no matter how complex.

Design considerations MotionLayout is intended to move, resize, and animate UI elements with which users interact, such as buttons and title bars. Motion in your app should not be simply a gratuitous special effect in your application. It should be used to help users understand what your application is doing. For more information on designing your app with motion, see the Material Design section on Understanding motion.

Getting started Follow these steps to start using MotionLayout in your project.

Add the ConstraintLayout dependency: To use MotionLayout in your project, add the ConstraintLayout 2.0 dependency to your app's build.gradle file. If you're using AndroidX, add the following dependency:

dependencies {
    implementation "androidx.constraintlayout:constraintlayout:2.1.4"
    // To use constraintlayout in compose
    implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"
}

Create a MotionLayout file: MotionLayout is a subclass of ConstraintLayout, so you can transform any existing ConstraintLayout into a MotionLayout by replacing the class name in your layout resource file, as shown in the following examples:

<!-- before: ConstraintLayout -->
<androidx.constraintlayout.widget.ConstraintLayout .../>
<!-- after: MotionLayout -->
<androidx.constraintlayout.motion.widget.MotionLayout .../>

Here's a full example MotionLayout file that can be used to create the motion in figure 1:

<?xml version="1.0" encoding="utf-8"?>
<!-- activity_main.xml -->
<androidx.constraintlayout.motion.widget.MotionLayout
    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:id="@ id/motionLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/scene_01"
    tools:showPaths="true">

    <View
        android:id="@ id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:background="@color/colorAccent"
        android:text="Button" />

</androidx.constraintlayout.motion.widget.MotionLayout>

Create a MotionScene: In the previous MotionLayout example, the app:layoutDescription attribute references a MotionScene. A MotionScene is an XML resource file that contains all of the motion descriptions for the corresponding layout. To keep layout information separate from motion descriptions, each MotionLayout references a separate MotionScene. Note that definitions in the MotionScene take precedence over any similar definitions in the MotionLayout.

Here's an example MotionScene file that describes the basic horizontal motion in figure 1:

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto">

    <Transition
        motion:constraintSetStart="@ id/start"
        motion:constraintSetEnd="@ id/end"
        motion:duration="1000">
        <OnSwipe
            motion:touchAnchorId="@ id/button"
            motion:touchAnchorSide="right"
            motion:dragDirection="dragRight" />
    </Transition>

    <ConstraintSet android:id="@ id/start">
        <Constraint
            android:id="@ id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_marginStart="8dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

    <ConstraintSet android:id="@ id/end">
        <Constraint
            android:id="@ id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_marginEnd="8dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

</MotionScene>
    

Note the following:

contains the base definition of the motion.

motion:constraintSetStart and motion:constraintSetEnd are references to the endpoints of the motion. These endpoints are defined in the elements later in the MotionScene.

motion:duration specifies the number of milliseconds that it takes for the motion to complete.

lets you control the motion via touch.

motion:touchAnchorId refers to the view that you can swipe and drag.

motion:touchAnchorSide means that we are dragging the view from the right side.

motion:dragDirection refers to the progress direction of the drag. For example, motion:dragDirection="dragRight" means that progress increases as you drag to the right.

is where you define the various constraints that describe your motion. In this example, we define one ConstraintSet for each endpoint of our motion. These endpoints are centered vertically (via app:layout_constraintTop_toTopOf="parent" and app:layout_constraintBottom_toBottomOf="parent"). Horizontally, the endpoints are at the far left and right sides of the screen.

For a more detailed look at the various elements that MotionScene supports, see the MotionLayout examples.

Interpolated attributes Within a MotionScene file, ConstraintSet elements can contain additional attributes that are interpolated during transition. In addition to position and bounds, the following attributes are interpolated by MotionLayout:

alpha visibility elevation rotation, rotationX, rotationY translationX, translationY, translationZ scaleX, scaleY Custom attributes Within a , you can use the element to specify a transition for attributes that aren't simply related to position or View attributes.

<Constraint
    android:id="@ id/button" ...>
    <CustomAttribute
        motion:attributeName="backgroundColor"
        motion:customColorValue="#D81B60"/>
</Constraint>

A contains two attributes of its own:

motion:attributeName is required and must match an object with getter and setter methods. The getter and setter must match a specific pattern. For example, backgroundColor is supported, since our view has underlying getBackgroundColor() and setBackgroundColor() methods. The other attribute you must provide is based on the value type. Choose from the following supported types: motion:customColorValue for colors motion:customIntegerValue for integers motion:customFloatValue for floats motion:customStringValue for strings motion:customDimension for dimensions motion:customBoolean for booleans Note that when specifying a custom attribute, you must define endpoint values in both the start and end elements.

Example: Change background color Building on our previous example, let's have the view change colors as part of its motion, as shown in figure 2.

enter image description here

Figure 2. The view changes its background color as it moves. Add a element to each ConstraintSet elements, as shown below:

<ConstraintSet android:id="@ id/start">
    <Constraint
        android:id="@ id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginStart="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintStart_toStartOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#D81B60" />
    </Constraint>
</ConstraintSet>

<ConstraintSet android:id="@ id/end">
    <Constraint
        android:id="@ id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginEnd="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintEnd_toEndOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#9999FF" />
    </Constraint>
</ConstraintSet>

Additional MotionLayout attributes In addition to the attributes in the example above, MotionLayout has other attributes that you might want to specify:

app:applyMotionScene="boolean" indicates whether to apply the MotionScene. The default value for this attribute is true. app:showPaths="boolean" indicates whether to show the motion paths as the motion is running. The default value for this attribute is false. app:progress="float" lets you explicitly specify transition progress. You can use any floating-point value from 0 (the start of the transition) to 1 (the end of the transition). app:currentState="reference" lets you specify a specific ConstraintSet. app:motionDebug lets you display additional debug information about the motion. Possible values are "SHOW_PROGRESS", "SHOW_PATH", or "SHOW_ALL".

  • Related