I have a fragment A with a CollapsingToolbarLayout containing a view that collapses when scrolling the page.
At the end of the page, a button navigates to another fragment B.
When I press back on fragment B, fragment B is removed from the navigation stack and fragment A is shown again from the previous position (scroll at the bottom).
Right now everything is ok, but the toolbar of fragment A is initially visible and then collapses during the transition, even if it should not be visible.
This is the layout of Fragment A:
<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
style="?attr/collapsingToolbarLayoutLargeStyle"
android:layout_width="match_parent"
android:layout_height="280dp"
android:fitsSystemWindows="true"
app:contentScrim="?android:colorBackground"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:scrimVisibleHeightTrigger="70dp"
app:statusBarScrim="?android:colorBackground">
<View
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#ff0000"
android:fitsSystemWindows="true" />
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/topAppBar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="0dp"
android:fitsSystemWindows="false"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways"
app:navigationIcon="@drawable/chevron_back"
app:navigationIconTint="#00ff00" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:fillViewport="true"
android:orientation="vertical"
android:paddingHorizontal="@dimen/content_padding"
android:paddingTop="0dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/short_description"
style="@style/body_gray"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:text="@string/lorem_ipsum" />
<Button
android:id="@+id/next"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:text="Next" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
And this is its code:
class FragmentA: Fragment() {
private var _binding: FragmentABinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
_binding = FragmentABinding.inflate(inflater, container, false)
binding.topAppBar.setNavigationOnClickListener {
findNavController().popBackStack()
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.next.setOnClickListener {
findNavController().navigate(R.id.action_A_to_B)
)
}
}
}
This is the action used for the navigation:
<action
android:id="@+id/action_A_to_B"
app:destination="@id/fragmentb"
app:enterAnim="@anim/slide_in"
app:exitAnim="@anim/slide_out"
app:popEnterAnim="@anim/pop_in"
app:popExitAnim="@anim/pop_out"
app:launchSingleTop="true"/>
This is the video of the glitch: https://youtube.com/shorts/0UKtAwOSZQI
This is a minimal project that replicates the problem: https://mega.nz/file/lq5AEY6T#A-PxuVcWGDLSSktGHLwmtfMBgfUYu659EF7LbP770S8
The problem causing that glitch is that the scrim animation of the CollapsingToolbarLayout
is enabled by default, so it takes time to fade out the CollapsingToolbarLayout
color.
This can be solved by disabling the scrim animation by setting its duration to 0 using app:scrimAnimationDuration
attribute:
<androidx.coordinatorlayout.widget.CoordinatorLayout
....>
<com.google.android.material.appbar.AppBarLayout
....>
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
app:scrimAnimationDuration="0">
...
Well, although disabling the scrim animation will solve the issue, but it will raise another whenever the CollapsingToolbarLayout
get collapsed or expanded by dragging it up or down; so we need to conditionally disable the scrim animation.
Now remove the app:scrimAnimationDuration="0"
from the layout.
We need to keep the scrim animation ON by default, but only when we returned back from Fragment B
to Fragment A
we need to disable it and re-enable it again:
// In Fragment A
override fun onResume() {
super.onResume()
// Make sure to save that on a permanent storage like ViewModel to avoid losing it.
val duration = binding.collapsingToolbar.scrimAnimationDuration
// Disable the animation
binding.collapsingToolbar.scrimAnimationDuration = 0
Handler(Looper.getMainLooper()).postDelayed({
// Re-Enable the animation
binding.collapsingToolbar.scrimAnimationDuration = duration
}, duration)
}