Skip to content

Latest commit

 

History

History
230 lines (172 loc) · 8.39 KB

11. Running Motion with Code.md

File metadata and controls

230 lines (172 loc) · 8.39 KB

11. Running Motion with Code

MotionLayout can be used to build rich animations when used with CoordinatorLayout. In this step, we'll build a collapsible header using MotionLayout.

After we complete this step we'll have built this animation.

Running Motion with Code

  1. Create a new empty activity -> EleventhActivity.

  2. Save the below given code to the file activity_eleventh.xml ->

     <androidx.coordinatorlayout.widget.CoordinatorLayout
     	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"
     	tools:context=".EleventhActivity">
    
     	<com.google.android.material.appbar.AppBarLayout
     		android:id="@+id/app_bar_layout"
     		android:layout_width="match_parent"
     		android:layout_height="180dp">
    
     		<androidx.constraintlayout.motion.widget.MotionLayout
     			android:id="@+id/motion_layout"
     			android:layout_width="match_parent"
     			android:layout_height="match_parent"
     			android:minHeight="80dp"
     			app:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed"
     			app:layoutDescription="@xml/activity_eleventh_scene"
     			app:motionDebug="NO_DEBUG">
    
     			<ImageView
     				android:id="@+id/background"
     				android:layout_width="0dp"
     				android:layout_height="1000dp"
     				app:layout_constraintTop_toTopOf="parent"
     				app:layout_constraintBottom_toBottomOf="parent"
     				app:layout_constraintStart_toStartOf="parent"
     				app:layout_constraintEnd_toEndOf="parent"
     				android:scaleType="centerCrop"
     				android:contentDescription="@string/background"
     				app:srcCompat="@drawable/background"/>
    
     			<ImageView
     				android:id="@+id/moon"
     				android:layout_width="wrap_content"
     				android:layout_height="wrap_content"
     				app:srcCompat="@drawable/moon"
     				android:tint="?colorOnPrimary"
     				android:contentDescription="@string/moon"/>
    
     			<TextView
     				android:id="@+id/credits"
     				android:layout_width="wrap_content"
     				android:layout_height="wrap_content"
     				android:text="@string/credits"
     				android:textSize="24sp"
     				android:textColor="?colorOnPrimary"/>
    
     		</androidx.constraintlayout.motion.widget.MotionLayout>
    
     	</com.google.android.material.appbar.AppBarLayout>
    
     	<androidx.core.widget.NestedScrollView
     		android:layout_width="match_parent"
     		android:layout_height="match_parent"
     		app:layout_behavior="@string/appbar_scrolling_view_behavior">
    
     		<TextView
     			android:layout_width="wrap_content"
     			android:layout_height="wrap_content"
     			android:text="@string/longText"/>
    
     	</androidx.core.widget.NestedScrollView>
    
     </androidx.coordinatorlayout.widget.CoordinatorLayout>
    
  3. Create a new XML Resource File -> app -> res -> xml -> activity_eleventh_scene.xml.

  4. Save the below given code to the file activity_eleventh_scene.xml ->

     <!-- Describe the animation for activity_eleventh.xml -->
     <MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
     	xmlns:app="http://schemas.android.com/apk/res-auto">
    
     	<!-- A transition describes an animation via start and end state -->
     	<Transition
     		app:constraintSetEnd="@+id/end"
     		app:constraintSetStart="@+id/start">
    
     		<KeyFrameSet>
    
     			<KeyPosition
     				app:framePosition="25"
     				app:keyPositionType="parentRelative"
     				app:motionTarget="@id/moon"
     				app:percentY="0.6" />
    
     			<KeyPosition
     				app:framePosition="50"
     				app:keyPositionType="parentRelative"
     				app:motionTarget="@id/moon"
     				app:percentY="0.5" />
    
     			<KeyPosition
     				app:framePosition="75"
     				app:keyPositionType="parentRelative"
     				app:motionTarget="@id/moon"
     				app:percentY="0.6" />
    
     			<KeyAttribute
     				app:framePosition="50"
     				app:motionTarget="@id/moon" />
    
     			<KeyAttribute
     				app:framePosition="100"
     				app:motionTarget="@id/moon" />
    
     			<KeyAttribute
     				android:alpha="0.0"
     				app:framePosition="85"
     				app:motionTarget="@id/credits" />
    
     			<KeyAttribute
     				android:translationY="500dp"
     				app:framePosition="100"
     				app:motionTarget="@id/background" />
    
     		</KeyFrameSet>
    
     	</Transition>
    
     	<!-- Constraints to apply at the start of the animation -->
     	<ConstraintSet android:id="@+id/start">
    
     		<Constraint
     			android:id="@id/moon"
     			android:layout_width="wrap_content"
     			android:layout_height="wrap_content"
     			app:layout_constraintBottom_toBottomOf="parent"
     			app:layout_constraintStart_toStartOf="parent" />
    
     		<Constraint
     			android:id="@id/credits"
     			android:layout_width="wrap_content"
     			android:layout_height="wrap_content"
     			android:layout_marginStart="16dp"
     			android:alpha="0.0"
     			app:layout_constraintBottom_toBottomOf="@id/moon"
     			app:layout_constraintStart_toStartOf="parent"
     			app:layout_constraintTop_toTopOf="@id/moon" />
    
     	</ConstraintSet>
    
     	<!-- Constraints to apply at the end of the animation -->
     	<ConstraintSet android:id="@+id/end">
    
     		<Constraint
     			android:id="@id/moon"
     			android:layout_width="60dp"
     			android:layout_height="60dp"
     			android:layout_marginBottom="10dp"
     			app:layout_constraintBottom_toBottomOf="parent"
     			app:layout_constraintEnd_toEndOf="parent" />
    
     		<Constraint
     			android:id="@id/credits"
     			android:layout_width="wrap_content"
     			android:layout_height="wrap_content"
     			android:layout_marginStart="16dp"
     			android:alpha="1.0"
     			app:layout_constraintBottom_toBottomOf="@id/moon"
     			app:layout_constraintStart_toStartOf="parent"
     			app:layout_constraintTop_toTopOf="@id/moon" />
    
     	</ConstraintSet>
    
     </MotionScene>
    
  5. Save the below given code the the file EleventhActivity.java ->

     public class EleventhActivity extends AppCompatActivity {
    
     	@Override
     	protected void onCreate(Bundle savedInstanceState) {
     		super.onCreate(savedInstanceState);
     		setContentView(R.layout.activity_eleventh);
    
     		coordinateMotion();
     	}
    
     	private void coordinateMotion() {
     		AppBarLayout appBarLayout = findViewById(R.id.app_bar_layout);
     		final MotionLayout motionLayout = findViewById(R.id.motion_layout);
    
     		appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
     			@Override
     			public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
     				motionLayout.setProgress(-verticalOffset / Float.valueOf(appBarLayout.getTotalScrollRange()));
     			}
     		});
     	}
     }
    
  6. Run and Test the application.

This layout uses a CoordinatorLayout to share scrolling information between the NestedScrollView and the AppBarLayout. So, when the NestedScrollView scrolls up, it will tell the AppBarLayout about the change. That's how we implement a collapsing toolbar like this on Android—the scrolling of the text will be "coordinated" with the collapsing header.

The motion scene that @id/motion_layout points to is similar to the motion scene in the last step. However, the OnSwipe declaration was removed to enable it to work with CoordinatorLayout.

To make the MotionLayout view scroll as soon as the NestedScrollView scrolls, add app:minHeight and app:layout_scrollFlags to the MotionLayout.

This code will register a OnOffsetChangedListener that will be called every time the user scrolls with the current scroll offset.

MotionLayout supports seeking its transition by setting the progress property. To convert between a verticalOffset and a percentage progress, divide by the total scroll range.

MotionLayout can seek to a specific point in the animation in code.

Do this by setting motionLayout.progress. MotionLayout will immediately "jump" to the position that was specified.

So, for example, if we set the progress to 0.43, MotionLayout will jump to 43% through the animation.

It's possible to build custom dynamic collapsing toolbar animations using MotionLayout. By using a sequence of KeyFrames we can achieve very bold effects.

AppBarLayout does not resize the MotionLayout.

The MotionLayout view will be moved partially offscreen when AppBarLayout collapses it. It will not be resized, but just moved up. If we have constraints to the top of the MotionLayout, they will be offscreen at the end of the animation. To work with AppBarLayout ensure end constraints are anchored to the bottom of the parent.