[Snackbar] Snackbar bottom margin is incorrect when using window insets with padding
Description:
Snackbar with anchor has incorrect bottom margin when window insets are used that set container padding instead of margin.
When insets update margin, snackbar is shown correctly above the anchor button.
When insets update padding, snackbar gets extra bottom margin. It seems that navigation bar height is used twice.
Expected behavior: Snackbar should always be displayed right above the anchor.
Source code:
The issue is most probably somewhere in BaseTransientBottomBar, but I wasn't able to identify exact place.
Minimal sample app repro:
https://github.com/aleksandra-krzemien/nested-nav-graphs-example/tree/krzemien/snackbar-inset-handling
Tap on to first fragment button to open FirstFragment. Current code will use insets with margin, so you will see situation on the first screenshot above (correct).
If you comment FirstFragment lines 41-43 and uncomment line 45, insets will update padding, and you'll end up with situation from second screenshot (incorrect).
Android API version: 29
Material Library version: 1.9.0
Device: Pixel 4a
I'm seeing something similar since the 1.7.0 release and going edge-to-edge, but without an anchor view: with a CoordinatorLayout and BottomNavigationView stacked in a LinearLayout (see below).
The culprit seems to be the OnApplyWindowInsetsListener which always adds the bottom window inset as bottom margin to the BaseTransientBottomBar. Basically, the Snackbar assumes it always is aligned with the bottom of the window.
Question is if this is considered a bug or a layout/configuration issue (in which way)?
https://github.com/material-components/material-components-android/blob/cbb380df61f8eb66273043b437582c8058df7088/lib/java/com/google/android/material/snackbar/BaseTransientBottomBar.java#L396-L410 https://github.com/material-components/material-components-android/blob/cbb380df61f8eb66273043b437582c8058df7088/lib/java/com/google/android/material/snackbar/BaseTransientBottomBar.java#L479-L483
Example layout, the Snackbar is launched with the CoordinatorLayout as the parent view:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<include layout="@layout/top_app_bar" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPagerTabs"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginStart="0dp"
android:layout_marginTop="0dp"
android:layout_marginEnd="@dimen/fab_margin"
android:layout_marginBottom="@dimen/fab_margin"
app:srcCompat="@drawable/ic_add_white_24dp" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:labelVisibilityMode="labeled"
app:menu="@menu/bottom_navigation_menu" />
</LinearLayout>
Snackbar.make(findViewById(R.id.coordinatorLayout), "message", Snackbar.LENGTH_LONG).show()
Good morning! Any update on this bug? It seems still present in 1.12.0 Is there any workaround? Edge-to-edge is going to be inforced with targetSdk = 35 ...
Any updates here? We are also experiencing the same issue.
Our app is also affected by this and was trying to see why. Looks like this is where the snackbar container gets it's system navigation bar padding.
Thinking more about this, showing the snackbar above the system navigation bar is a valid concern and handling it in BaseTransientBottomBar instead of asking each app to handle this seems preferable.
Having BaseTransientBottomBar somehow support apps using edge-to-edge is a bit tricky since I don't think there is an API to determine if the app is in edge-to-edge mode and apps can use this or not on <= API 35.
Would think that anchoring the snackbar is rather an edgecase so maybe keeping the current functionality for most apps would still be better and then each app using edge-to-edge would handle themselves the positioning of the snackbar - maybe with using translationY instead of anchoring where they could easily consider the navigation bar inset.
This issue is aggravated by the WindowInsetListener also considering the IME which is dynamic. <=> If a bottom snackbar is shown at the same time with the IME then it will be pushed to the top of the screen with a padding being equal to the sum of the OS navigation bar height + the IME height.
And because this padding is set dynamically inside of BaseTransientBottomBar it's hard to perfectly match reverting it from outside (without flickering) => we need an API to disable this internal behavior.
Looks like we can take advantage of this check for the parent of the snackbar providing MarginLayoutParams and so we can use a ConstraintLayout? container for the snackbar and then anchor that container avoid the discussed issues.
I ran into this issue, but it turns out the fix was simply to return WindowInsetsCompat.CONSUMED from setOnApplyWindowInsetsListener instead of the yielded parameter
@ygnessin Thank you so much. Your workaround works!
"In my case, I wasn’t able to easily consume this callback from outside.
So I called getView() on the Snackbar and set an OnApplyWindowInsetsListener on it before showing. This successfully removed the extra margin."