[Snackbar] Added optional close icon

PiperOrigin-RevId: 845256053
This commit is contained in:
hunterstich 2025-12-16 15:08:41 +00:00 committed by Hunter Stich
parent d5934ee5ba
commit 71f014fa41
19 changed files with 343 additions and 22 deletions

View File

@ -19,6 +19,7 @@ package io.material.catalog.snackbar;
import io.material.catalog.R;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
@ -89,6 +90,7 @@ public class SnackbarMainDemoFragment extends DemoFragment {
Snackbar.LENGTH_SHORT)
.setAction(R.string.cat_snackbar_action_title, a -> {})
.setTextMaxLines(5)
.setCloseIconVisible(true)
.show();
});
@ -103,12 +105,39 @@ public class SnackbarMainDemoFragment extends DemoFragment {
Context c =
new ContextThemeWrapper(
v.getContext(), R.style.ThemeOverlay_Catalog_SnackbarWithCustomShape);
Snackbar.make(
Snackbar snackbar = Snackbar.make(
c,
coordinatorLayout,
getString(R.string.cat_snackbar_custom_shape_message),
Snackbar.LENGTH_SHORT)
.setAction("Done", a -> {})
.setCloseIconVisible(/* visible= */ true)
.setCloseIconResource(R.drawable.ic_cancel_24)
.setCloseIconTint(Color.GREEN);
// Setting the close icon to visible removes the snackbar layout's end padding. To
// customize this, get the snackbar's view and set the end padding to a value
// that fits nicely with the custom shape and icon.
View snackbarLayout = snackbar.getView();
snackbarLayout.setPaddingRelative(
snackbarLayout.getPaddingStart(),
snackbarLayout.getPaddingTop(),
getResources().getDimensionPixelSize(
R.dimen.cat_snackbar_custom_shape_end_padding),
snackbarLayout.getPaddingBottom()
);
snackbar.show();
});
// Snackbar with close icon
view.findViewById(R.id.with_close_button)
.setOnClickListener(
v -> {
Snackbar.make(
coordinatorLayout,
R.string.cat_snackbar_with_close_message,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.cat_snackbar_action_title, a -> {})
.setCloseIconVisible(true)
.show();
});
}

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2025 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M480,554L582.22,656.22Q597.22,671.22 618.93,671.22Q640.65,671.22 656.22,655.74Q671.78,640.27 671.78,618.74Q671.78,597.22 656.22,581.65L554,480L656.22,377.78Q671.22,362.78 671.5,341.07Q671.78,319.35 656.31,303.78Q640.83,288.22 619.31,288.22Q597.78,288.22 582.22,303.78L480,406L377.78,303.78Q362.78,288.78 341.35,288.5Q319.91,288.22 304.35,303.69Q288.78,319.17 288.78,340.69Q288.78,362.22 304.35,377.78L406,480L303.78,582.22Q288.78,597.22 288.78,618.65Q288.78,640.09 304.26,655.65Q319.73,671.22 341.26,671.22Q362.78,671.22 378.35,655.65L480,554ZM480,919.91Q388.66,919.91 308.13,885.61Q227.59,851.31 168.14,791.86Q108.69,732.41 74.39,651.87Q40.09,571.34 40.09,480Q40.09,388.41 74.45,307.93Q108.81,227.45 168.45,167.85Q228.1,108.25 308.44,74.17Q388.78,40.09 480,40.09Q571.58,40.09 652.08,74.16Q732.57,108.23 792.17,167.83Q851.77,227.43 885.84,307.95Q919.91,388.47 919.91,480.08Q919.91,571.7 885.83,651.8Q851.75,731.9 792.15,791.55Q732.55,851.19 652.07,885.55Q571.59,919.91 480,919.91ZM479.87,796.96Q613.12,796.96 705.04,705.17Q796.96,613.38 796.96,480.13Q796.96,346.88 705.17,254.96Q613.38,163.04 480.13,163.04Q346.88,163.04 254.96,254.83Q163.04,346.62 163.04,479.87Q163.04,613.12 254.83,705.04Q346.62,796.96 479.87,796.96ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z"/>
</vector>

View File

@ -52,6 +52,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cat_snackbar_custom_shape_button"/>
<Button
android:id="@+id/with_close_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cat_snackbar_with_close_button"/>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2025 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<dimen name="cat_snackbar_custom_shape_end_padding">12dp</dimen>
</resources>

View File

@ -59,6 +59,13 @@
Custom shape snackbar
</string>
<string name="cat_snackbar_custom_shape_message" description="The message of the snackbar with a custom background shape. [CHAR LIMIT=NONE]">
This is a snackbar with a custom shape
This is a snackbar with a custom shape with a customized close icon
</string>
<string name="cat_snackbar_with_close_button" description="The label of the button that launches a snackbar with a custom background shape. [CHAR LIMIT=NONE]">
Snackbar with close icon
</string>
<string name="cat_snackbar_with_close_message" description="The message of the snackbar with a custom background shape. [CHAR LIMIT=NONE]">
This is a snackbar with a close icon.
</string>
</resources>

View File

@ -16,10 +16,12 @@
-->
<resources>
<style name="ThemeOverlay.Catalog.SnackbarWithCustomShape" parent="Theme.Catalog">
<style name="ThemeOverlay.Catalog.SnackbarWithCustomShape" parent="">
<item name="snackbarStyle">@style/Widget.Catalog.Snackbar.PillShape</item>
</style>
<style name="Widget.Catalog.Snackbar.PillShape" parent="Widget.Material3.Snackbar">
<item name="shapeAppearance">@style/ShapeAppearance.Material3.Corner.Full</item>
<item name="android:paddingStart">24dp</item>
<item name="android:paddingEnd">12dp</item>
</style>
</resources>

View File

@ -71,13 +71,22 @@ Element | Attribute | Related method(s) | Defau
**Text color alpha** | `app:actionTextColorAlpha` | N/A | `1.0f`
**Text Color** | `android:textColor` | `setTextActionColor` | `?attr/colorPrimaryInverse`
### Close attributes
Element | Attribute | Related method(s) | Default value
-------------------------- |----------------|------------------------| -------------
**Close button style** | N/A | N/A | `?attr/snackbarCloseButtonStyle`
**Icon tint** | `app:iconTint` | `setCloseIconTint` | `?attr/colorOnSurfaceInverse`
**Icon** | `app:icon` | `setCloseIconResource` | `@drawable/mtrl_close_24px`
### Styles
Element | Theme attribute | Default value
----------------------- | ----------------------------- | -----------------
**Default style** | `?attr/snackbarStyle` | `@style/Widget.Material3.Snackbar`
**Action button style** | `?attr/snackbarButtonStyle` | `@style/Widget.Material3.Button.TextButton.Snackbar`
**Text label style** | `?attr/snackbarTextViewStyle` | `@style/Widget.Material3.Snackbar.TextView`
Element | Theme attribute | Default value
------------------------- |----------------------------------| -----------------
**Default style** | `?attr/snackbarStyle` | `@style/Widget.Material3.Snackbar`
**Action button style** | `?attr/snackbarButtonStyle` | `@style/Widget.Material3.Button.TextButton.Snackbar`
**Text label style** | `?attr/snackbarTextViewStyle` | `@style/Widget.Material3.Snackbar.TextView`
**Close button style** | `?attr/snackbarCloseButtonStyle` | `@style/Widget.Material3.Button.IconButton.Close.Snackbar`
For the full list, see
[styles](https://github.com/material-components/material-components-android/tree/master/lib/java/com/google/android/material/snackbar/res/values/styles.xml)
@ -196,6 +205,18 @@ Snackbar.make(contextView, R.string.text_label, Snackbar.LENGTH_LONG)
.show()
```
### Adding a close button
To add a close button to the end of the snackbar, use the `setCloseIconVisible`
method on the object returned from `make`. Snackbars are automatically dismissed
when the close button is clicked.
```kt
Snackbar.make(contextView, R.string.text_label, Snackbar.LENGTH_INDEFINITE)
.setCloseIconVisible(true)
.show()
```
## Customizing snackbar
### Theming snackbar

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2025 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>

View File

@ -20,4 +20,5 @@
<string name="mtrl_button_collapsed_content_description" description="An announcement for the collapsed menu state of the trailing button in split button [CHAR LIMIT=NONE]">Collapsed</string>
<!-- Content description for the overflow button. -->
<string name="mtrl_button_overflow_icon_content_description" description="Content description for the overflow button of the button group. [CHAR LIMIT=NONE]">Overflow menu</string>
<string name="mtrl_button_snackbar_close_content_description" description="Content description for the close button of the Snackbar. [CHAR LIMIT=NONE]">Close</string>
</resources>

View File

@ -729,6 +729,15 @@
<item name="materialThemeOverlay">@style/ThemeOverlay.Material3.Button.TextButton.Snackbar</item>
</style>
<style name="Widget.Material3.Button.IconButton.Close.Snackbar" parent="Widget.Material3.Button.IconButton">
<item name="android:minWidth">@dimen/mtrl_min_touch_target_size</item>
<item name="android:paddingStart">12dp</item>
<item name="android:paddingEnd">12dp</item>
<item name="android:contentDescription">@string/mtrl_button_snackbar_close_content_description</item>
<item name="icon">@drawable/mtrl_close_24px</item>
<item name="iconTint">?attr/colorOnSurfaceInverse</item>
</style>
<!-- M3 outlined button style. -->
<style name="Widget.Material3.Button.OutlinedButton" parent="Widget.Material3.Button.TextButton">
<item name="android:paddingLeft">@dimen/m3_btn_padding_left</item>
@ -949,6 +958,14 @@
<item name="android:textColor">?attr/colorPrimary</item>
</style>
<style name="Widget.MaterialComponents.Button.TextButton.Icon.Close.Snackbar" parent="Widget.Material3.Button.TextButton.Icon">
<item name="android:alpha">@dimen/material_emphasis_high_type</item>
<item name="android:minWidth">@dimen/mtrl_min_touch_target_size</item>
<item name="android:contentDescription">@string/mtrl_button_snackbar_close_content_description</item>
<item name="icon">@drawable/mtrl_close_24px</item>
<item name="iconTint">?attr/colorSurface</item>
</style>
<style name="Widget.MaterialComponents.Button.OutlinedButton" parent="Widget.MaterialComponents.Button.TextButton">
<item name="android:paddingLeft">@dimen/mtrl_btn_padding_left</item>
<item name="android:paddingRight">@dimen/mtrl_btn_padding_right</item>

View File

@ -321,6 +321,7 @@
<item name="snackbarStyle">@style/Widget.Material3.Snackbar</item>
<item name="snackbarButtonStyle">@style/Widget.Material3.Button.TextButton.Snackbar</item>
<item name="snackbarTextViewStyle">@style/Widget.Material3.Snackbar.TextView</item>
<item name="snackbarCloseButtonStyle">@style/Widget.Material3.Button.IconButton.Close.Snackbar</item>
<item name="switchStyle">@style/Widget.Material3.CompoundButton.Switch</item>
<item name="tabStyle">@style/Widget.Material3.TabLayout</item>
<item name="tabSecondaryStyle">@style/Widget.Material3.TabLayout.Secondary</item>
@ -643,6 +644,7 @@
<item name="snackbarStyle">@style/Widget.Material3.Snackbar</item>
<item name="snackbarButtonStyle">@style/Widget.Material3.Button.TextButton.Snackbar</item>
<item name="snackbarTextViewStyle">@style/Widget.Material3.Snackbar.TextView</item>
<item name="snackbarCloseButtonStyle">@style/Widget.Material3.Button.IconButton.Close.Snackbar</item>
<item name="switchStyle">@style/Widget.Material3.CompoundButton.Switch</item>
<item name="tabStyle">@style/Widget.Material3.TabLayout</item>
<item name="tabSecondaryStyle">@style/Widget.Material3.TabLayout.Secondary</item>
@ -859,6 +861,7 @@
<item name="snackbarStyle">@style/Widget.MaterialComponents.Snackbar</item>
<item name="snackbarButtonStyle">@style/Widget.MaterialComponents.Button.TextButton.Snackbar</item>
<item name="snackbarTextViewStyle">@style/Widget.MaterialComponents.Snackbar.TextView</item>
<item name="snackbarCloseButtonStyle">@style/Widget.MaterialComponents.Button.TextButton.Icon.Close.Snackbar</item>
<item name="switchStyle">@style/Widget.MaterialComponents.CompoundButton.Switch</item>
<item name="tabStyle">@style/Widget.MaterialComponents.TabLayout</item>
<item name="textInputStyle">@style/Widget.MaterialComponents.TextInputLayout.FilledBox</item>
@ -916,6 +919,7 @@
<item name="snackbarStyle">@style/Widget.MaterialComponents.Snackbar</item>
<item name="snackbarButtonStyle">@style/Widget.MaterialComponents.Button.TextButton.Snackbar</item>
<item name="snackbarTextViewStyle">@style/Widget.MaterialComponents.Snackbar.TextView</item>
<item name="snackbarCloseButtonStyle">@style/Widget.MaterialComponents.Button.TextButton.Icon.Close.Snackbar</item>
<item name="switchStyle">@style/Widget.MaterialComponents.CompoundButton.Switch</item>
<item name="tabStyle">@style/Widget.MaterialComponents.TabLayout</item>
<item name="textInputStyle">@style/Widget.MaterialComponents.TextInputLayout.FilledBox</item>

View File

@ -1147,6 +1147,7 @@ public abstract class BaseTransientBottomBar<B extends BaseTransientBottomBar<B>
@Nullable private Rect originalMargins;
private boolean addingToTargetParent;
private final int originalPaddingEnd;
protected SnackbarBaseLayout(@NonNull Context context) {
this(context, null);
@ -1183,6 +1184,8 @@ public abstract class BaseTransientBottomBar<B extends BaseTransientBottomBar<B>
a.getDimensionPixelSize(R.styleable.SnackbarLayout_maxActionInlineWidth, -1);
a.recycle();
originalPaddingEnd = getPaddingEnd();
setOnTouchListener(consumeAllTouchListener);
setFocusable(true);
@ -1326,6 +1329,25 @@ public abstract class BaseTransientBottomBar<B extends BaseTransientBottomBar<B>
new Rect(params.leftMargin, params.topMargin, params.rightMargin, params.bottomMargin);
}
/**
* Remove or restore end padding from this view.
*
* The original padding is saved during inflation and removed or replaced depending
* on {@code remove}. This is used when calling enabling the Snackbar close icon as the icon
* should be flush with the end of the snackbar layout.
*
* @param remove true to set end padding to zero, false to restore the original
* end padding value
*/
void removeOrRestorePaddingEnd(boolean remove) {
setPaddingRelative(
getPaddingStart(),
getPaddingTop(),
remove ? 0 : originalPaddingEnd,
getPaddingBottom()
);
}
@NonNull
private Drawable createThemedBackground() {
int backgroundColor =

View File

@ -27,6 +27,7 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.text.TextUtils;
@ -41,11 +42,13 @@ import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.Dimension;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.StringRes;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.button.MaterialButton;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
/**
@ -88,12 +91,16 @@ public class Snackbar extends BaseTransientBottomBar<Snackbar> {
public static class Callback extends BaseCallback<Snackbar> {
/** Indicates that the Snackbar was dismissed via a swipe. */
public static final int DISMISS_EVENT_SWIPE = BaseCallback.DISMISS_EVENT_SWIPE;
/** Indicates that the Snackbar was dismissed via an action click. */
public static final int DISMISS_EVENT_ACTION = BaseCallback.DISMISS_EVENT_ACTION;
/** Indicates that the Snackbar was dismissed via a timeout. */
public static final int DISMISS_EVENT_TIMEOUT = BaseCallback.DISMISS_EVENT_TIMEOUT;
/** Indicates that the Snackbar was dismissed via a call to {@link #dismiss()}. */
public static final int DISMISS_EVENT_MANUAL = BaseCallback.DISMISS_EVENT_MANUAL;
/** Indicates that the Snackbar was dismissed from a new Snackbar being shown. */
public static final int DISMISS_EVENT_CONSECUTIVE = BaseCallback.DISMISS_EVENT_CONSECUTIVE;
@ -368,6 +375,82 @@ public class Snackbar extends BaseTransientBottomBar<Snackbar> {
return this;
}
/**
* Show an optional close icon at the end of the snackbar.
*
* <p>The close icon is set to {@code View.GONE} by default. Setting the icon to visible will show
* the icon at the end of the layout and automatically dismiss the snackbar when clicked. This
* method and other related closeIcon setters can only be used within the context of a Material 3
* or greater theme.
*
* <p>When using a close icon, please consider setting the snackbar's duration to {@code
* Snackbar.LENGTH_INDEFINITE}.
*
* <p>This method will automatically remove any end padding from the snackbar layout to properly
* align the close icon button. To manually set end padding, use {@link Snackbar#getView()} and
* call {@link View#setPaddingRelative(int, int, int, int)} before showing the snackbar.
*
* @param visible true to make the close icon visible
*/
@NonNull
@CanIgnoreReturnValue
public Snackbar setCloseIconVisible(boolean visible) {
final Button closeButton = getCloseViewOrThrow();
int newVisibility = visible ? View.VISIBLE : View.GONE;
closeButton.setVisibility(newVisibility);
closeButton.setOnClickListener(visible ? v -> dismiss() : null);
getSnackbarLayout().removeOrRestorePaddingEnd(/* remove= */ visible);
return this;
}
/**
* Set the tint color of the optional close icon.
*
* @param tint the tint color to be used for the close icon
*/
@NonNull
@CanIgnoreReturnValue
public Snackbar setCloseIconTint(@ColorInt int tint) {
return setCloseIconTintList(ColorStateList.valueOf(tint));
}
/**
* Set the tint list of the optional close icon.
*
* @param tintList the tint list to be used for the close icon
*/
@NonNull
@CanIgnoreReturnValue
public Snackbar setCloseIconTintList(@Nullable ColorStateList tintList) {
getCloseViewOrThrow().setIconTint(tintList);
return this;
}
/**
* Set the drawable used for the optional close icon.
*
* @param icon the drawable for the close icon
*/
@NonNull
@CanIgnoreReturnValue
public Snackbar setCloseIconDrawable(@Nullable Drawable icon) {
getCloseViewOrThrow().setIcon(icon);
return this;
}
/**
* Set the drawable resource used for the optional close icon.
*
* @param iconResourceId the drawable resource id for the close icon
*/
@NonNull
@CanIgnoreReturnValue
public Snackbar setCloseIconResource(@DrawableRes int iconResourceId) {
getCloseViewOrThrow().setIconResource(iconResourceId);
return this;
}
@Override
@Duration
public int getDuration() {
@ -550,4 +633,19 @@ public class Snackbar extends BaseTransientBottomBar<Snackbar> {
private SnackbarContentLayout getContentLayout() {
return (SnackbarContentLayout) view.getChildAt(0);
}
@NonNull
private MaterialButton getCloseViewOrThrow() {
if (!(getContentLayout().getCloseView() instanceof MaterialButton)) {
throw new IllegalStateException(
"The layout of this snackbar does not include a close MaterialButton. This might be"
+ " because the context's theme is not a Material 3 or later theme or because the"
+ " Snackbar's layout has been replaced with a custom layout.");
}
return (MaterialButton) getContentLayout().getCloseView();
}
private SnackbarBaseLayout getSnackbarLayout() {
return view;
}
}

View File

@ -39,6 +39,7 @@ import com.google.android.material.motion.MotionUtils;
public class SnackbarContentLayout extends LinearLayout implements ContentViewCallback {
private TextView messageView;
private Button actionView;
@Nullable private Button closeView;
private final TimeInterpolator contentInterpolator;
private int maxInlineActionWidth;
@ -61,6 +62,7 @@ public class SnackbarContentLayout extends LinearLayout implements ContentViewCa
super.onFinishInflate();
messageView = findViewById(R.id.snackbar_text);
actionView = findViewById(R.id.snackbar_action);
closeView = findViewById(R.id.mtrl_snackbar_close);
}
public TextView getMessageView() {
@ -71,6 +73,11 @@ public class SnackbarContentLayout extends LinearLayout implements ContentViewCa
return actionView;
}
@Nullable
public Button getCloseView() {
return closeView;
}
void updateActionTextColorAlphaIfNeeded(float actionTextColorAlpha) {
if (actionTextColorAlpha != 1) {
int originalActionTextColor = actionView.getCurrentTextColor();

View File

@ -19,6 +19,7 @@
<public name="snackbarStyle" type="attr"/>
<public name="snackbarButtonStyle" type="attr"/>
<public name="snackbarTextViewStyle" type="attr"/>
<public name="snackbarCloseButtonStyle" type="attr"/>
<public name="Widget.Design.Snackbar" type="style"/>
<public name="Widget.MaterialComponents.Snackbar" type="style"/>
<public name="Widget.MaterialComponents.Snackbar.FullWidth" type="style"/>

View File

@ -15,8 +15,7 @@
~ limitations under the License.
-->
<view
xmlns:android="http://schemas.android.com/apk/res/android"
<view xmlns:android="http://schemas.android.com/apk/res/android"
class="com.google.android.material.snackbar.SnackbarContentLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -39,4 +38,12 @@
android:minWidth="48dp"
android:visibility="gone"/>
<Button
android:id="@+id/mtrl_snackbar_close"
style="?attr/snackbarCloseButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|right|end"
android:visibility="gone"/>
</view>

View File

@ -23,6 +23,8 @@
<attr name="snackbarButtonStyle" format="reference"/>
<!-- Style to use for message text within a Snackbar in this theme. -->
<attr name="snackbarTextViewStyle" format="reference"/>
<!-- Style to use for the close icon within a Snackbar in this theme. -->
<attr name="snackbarCloseButtonStyle" format="reference"/>
</declare-styleable>
<declare-styleable name="SnackbarLayout">

View File

@ -342,6 +342,7 @@
<item name="snackbarStyle">@style/Widget.Material3.Snackbar</item>
<item name="snackbarButtonStyle">@style/Widget.Material3.Button.TextButton.Snackbar</item>
<item name="snackbarTextViewStyle">@style/Widget.Material3.Snackbar.TextView</item>
<item name="snackbarCloseButtonStyle">@style/Widget.Material3.Button.IconButton.Close.Snackbar</item>
<item name="switchStyle">@style/Widget.Material3.CompoundButton.Switch</item>
<item name="tabStyle">@style/Widget.Material3.TabLayout</item>
<item name="tabSecondaryStyle">@style/Widget.Material3.TabLayout.Secondary</item>
@ -667,6 +668,7 @@
<item name="snackbarStyle">@style/Widget.Material3.Snackbar</item>
<item name="snackbarButtonStyle">@style/Widget.Material3.Button.TextButton.Snackbar</item>
<item name="snackbarTextViewStyle">@style/Widget.Material3.Snackbar.TextView</item>
<item name="snackbarCloseButtonStyle">@style/Widget.Material3.Button.IconButton.Close.Snackbar</item>
<item name="switchStyle">@style/Widget.Material3.CompoundButton.Switch</item>
<item name="tabStyle">@style/Widget.Material3.TabLayout</item>
<item name="tabSecondaryStyle">@style/Widget.Material3.TabLayout.Secondary</item>
@ -861,6 +863,7 @@
<item name="snackbarStyle">@style/Widget.MaterialComponents.Snackbar</item>
<item name="snackbarButtonStyle">@style/Widget.MaterialComponents.Button.TextButton.Snackbar</item>
<item name="snackbarTextViewStyle">@style/Widget.MaterialComponents.Snackbar.TextView</item>
<item name="snackbarCloseButtonStyle">@style/Widget.MaterialComponents.Button.TextButton.Icon.Close.Snackbar</item>
<item name="switchStyle">@style/Widget.MaterialComponents.CompoundButton.Switch</item>
<item name="tabStyle">@style/Widget.MaterialComponents.TabLayout</item>
<item name="textInputStyle">@style/Widget.MaterialComponents.TextInputLayout.FilledBox</item>
@ -928,6 +931,7 @@
<item name="snackbarStyle">@style/Widget.MaterialComponents.Snackbar</item>
<item name="snackbarButtonStyle">@style/Widget.MaterialComponents.Button.TextButton.Snackbar</item>
<item name="snackbarTextViewStyle">@style/Widget.MaterialComponents.Snackbar.TextView</item>
<item name="snackbarCloseButtonStyle">@style/Widget.MaterialComponents.Button.TextButton.Icon.Close.Snackbar</item>
<item name="switchStyle">@style/Widget.MaterialComponents.CompoundButton.Switch</item>
<item name="tabStyle">@style/Widget.MaterialComponents.TabLayout</item>
<item name="textInputStyle">@style/Widget.MaterialComponents.TextInputLayout.FilledBox</item>

View File

@ -51,8 +51,7 @@ public class SnackbarTest {
ApplicationProvider.getApplicationContext()
.setTheme(R.style.Theme_MaterialComponents_Light_NoActionBar);
activity = Robolectric.buildActivity(AppCompatActivity.class).create().get();
accessibilityManager = Shadow.
extract(activity.getSystemService(Context.ACCESSIBILITY_SERVICE));
accessibilityManager = Shadow.extract(activity.getSystemService(Context.ACCESSIBILITY_SERVICE));
}
@Test
@ -60,11 +59,14 @@ public class SnackbarTest {
accessibilityManager.setTouchExplorationEnabled(true);
CoordinatorLayout view = new CoordinatorLayout(activity);
snackbar = Snackbar.make(view, "Test text", Snackbar.LENGTH_LONG).setAction("STUFF!",
new OnClickListener() {
@Override
public void onClick(View v) {}
});
snackbar =
Snackbar.make(view, "Test text", Snackbar.LENGTH_LONG)
.setAction(
"STUFF!",
new OnClickListener() {
@Override
public void onClick(View v) {}
});
assertThat(snackbar.getDuration()).isEqualTo(Snackbar.LENGTH_INDEFINITE);
}
@ -74,12 +76,30 @@ public class SnackbarTest {
accessibilityManager.setTouchExplorationEnabled(false);
CoordinatorLayout view = new CoordinatorLayout(activity);
snackbar = Snackbar.make(view, "Test text", 300).setAction("STUFF!",
new OnClickListener() {
@Override
public void onClick(View v) {}
});
snackbar =
Snackbar.make(view, "Test text", 300)
.setAction(
"STUFF!",
new OnClickListener() {
@Override
public void onClick(View v) {}
});
assertThat(snackbar.getDuration()).isEqualTo(300);
}
@Test
public void testCloseIcon_shouldRemoveLayoutEndPadding() {
CoordinatorLayout view = new CoordinatorLayout(activity);
snackbar =
Snackbar.make(
view,
"Snackbar with very very very very very very very very long message and"
+ " action.",
Snackbar.LENGTH_INDEFINITE)
.setAction("Action", v -> {})
.setCloseIconVisible(true);
assertThat(snackbar.view.getPaddingEnd()).isEqualTo(0);
}
}