От халепа... Ця сторінка ще не має українського перекладу, але ми вже над цим працюємо!
От халепа... Ця сторінка ще не має українського перекладу, але ми вже над цим працюємо!
Dmytro Ruban
/
Android Developer
4 min read
Creating a Collapsing Toolbar can be easily considered an essential part of an engaging design for Android application development. So how can we build it?
Well, there are two ways to do it.
So, in this article, I’ll show you how to create an Android Collapsing Toolbar with MotionLayout.
Article content:
Disclaimer: For continuing to read the article, just make sure that you’re familiar with MotionLayout and ConstraintLayout basics.
Basically, MotionLayout is a new class of the ConstraintLayout 2.0 library, which was announced back at Google IO 2018. Since then, it’s already been released to a stable beta version, so it’s become widely available and popular for android applications development.
Fundamentally, the tool helps Android app developers to handle motion and widget animation in their applications. As Nicolas Roard, one of the Google developers working on MotionLayout puts it:
in terms of capabilities, it’s like a mix between the property animation framework, TransitionManager, and CoordinatorLayout.
MotionLayout is primarily used in mobile application development when animating the UI elements a user will interact with. The second but not less critical purpose of applying the tool is to help users understand what your app actually does.
Now that we have a general meaning of MotionLayout and its possibilities, we should deal with the flesh implementation of a Collapsing Toolbar Android apps usually have.
The building process has two main parts. Let’s tap a toe into each of them step by step.
First, let’s see how our layout should look like:
<androidx.coordinatorlayout.widget.CoordinatorLayout> // This is our scrollable content: RecyclerView or NestedScrollView, etc. <androidx.recyclerview.widget.RecyclerView/> <com.google.android.material.appbar.AppBarLayout> <androidx.constraintlayout.motion.widget.MotionLayout // Inside MotionLayout, we will place our collapsing toolbar content </androidx.constraintlayout.motion.widget.MotionLayout> </com.google.android.material.appbar.AppBarLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>
Now we have to dive deeper into each component in our tree.
For proper content scrolling `app:layout_behavior=”@string/appbar_scrolling_view_behavior` must be set on the scrolling sibling (e.g., `NestedScrollView`, `RecyclerView`, etc.).
<androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
AppBarLayout must have a fixed height of an expanded state. Otherwise, MotionLayout behaves unpredictably. Please, keep this in mind as this is important.
<com.google.android.material.appbar.AppBarLayout android:id="@+id/app_bar_layout" android:layout_width="match_parent" android:layout_height="400dp" android:background="@android:color/white"> <androidx.constraintlayout.motion.widget.MotionLayout/> </com.google.android.material.appbar.AppBarLayout>
</com.google.android.material.appbar.AppBarLayout>
The next thing to do is to set `layout_height` to `match_parent` to keep MotionLayout a fixed height.
Attribute `minHeight` represents our collapsed toolbar height. We have to set it to system action bar size just to follow the same size to all collapsed toolbars across the app. However, you can set up any size you want.
Now, let’s proceed further. `layoutDescription` is a simple MotionScene with a start and end `ConstraintSets.`
Please note that this part doesn’t require any special activities. We don’t need to add any transitions triggers because the animation will be triggered programmatically after setting `layout_scrollFlags` the same as with the implementation of `CollapsingToolbarLayout.`
<androidx.constraintlayout.motion.widget.MotionLayout android:id="@+id/motion_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:minHeight="?attr/actionBarSize" app:layoutDescription="@xml/fragment_collapsing_motion_layout_scene" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> </androidx.constraintlayout.motion.widget.MotionLayout>
The biggest trick here is a proper transition between the expanded and collapsed state of our toolbar content.
To make it smooth and non-lagging, we need to define two guidelines: one for a collapsed state and another one for expanded.
The first guideline will be a guideline for insets. It must be constrained to begin. Thus, all content of the expanded toolbar must be constrained to it like to the top of the parent.
Consequently, we align all content from the start `ConstraintSet` to `insets_guideline` like to the top of the parent.
As we need setup insets in runtime, to have a look at a proper render in preview, let’s set `tools:layout_constraintGuide_begin=”24dp”.
<androidx.constraintlayout.widget.Guideline android:id="@+id/insets_guideline" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" tools:layout_constraintGuide_begin="24dp" />
Just as `insets_guideline` works as the top for the expanded state, our second guideline will serve as the bottom for the collapsed state and should be constrained to the end of the parent.
<androidx.constraintlayout.widget.Guideline android:id="@+id/collapsed_top_guideline" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" tools:layout_constraintGuide_end="?attr/actionBarSize" />
Now we have to connect `motionLayout` with `appBarLayout` to trigger animation through `OnOffsetChangedListener`.
Every time the Collapsing Toolbar should change its collapsed progress, it will inform us by just converting `verticalOffset` to a state of animation between 0f and 1f. It will allow us to inform MotionLayout about the new progress.
This action will be called every time the user scrolls an app.
binding.appBarLayout.addOnOffsetChangedListener( AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset -> val seekPosition = -verticalOffset / appBarLayout.totalScrollRange.toFloat() binding.motionLayout.progress = seekPosition } )
And finally, we set up guidelines with insets.
// Desired collapsed height of toolbar val toolBarHeight = binding.motionLayout.minimumHeight ViewCompat.setOnApplyWindowInsetsListener(requireView()) { v, insets -> // Resizing motion layout in a collapsed state with needed insets to not overlap system bars val insetHeight = insets.systemWindowInsetTop binding.motionLayout.minimumHeight = toolBarHeight + insetHeight // Update guidelines with givens insets val startConstraintSet = binding.motionLayout.getConstraintSet(R.id.start) startConstraintSet.setGuidelineBegin(R.id.insets_guideline, insetHeight) val endConstraintSet = binding.motionLayout.getConstraintSet(R.id.end) endConstraintSet.setGuidelineBegin(R.id.insets_guideline, insetHeight) endConstraintSet.setGuidelineEnd(R.id.collapsed_top_guideline, toolBarHeight ) insets }
Well, as we see, MotionLayout is pretty good at handling a Collapsing Toolbar.
There are a few more reasons to include MotionLayout into your animations.
All those above significantly enhance graphical tooling in Android Studio, as the core MotionLayout developers state.
Well, I hope that my thoughts and experiments were somehow helpful for you, and now you have a clear perception of how to build a Collapsing Toolbar with MotionLayout for your app.
Anyway, if you have any questions regarding this matter or any other topic in mobile app development for Android, please feel free to contact NERDZ LAB as your trustworthy Android app development company.