mirror of
https://github.com/material-components/material-components-android.git
synced 2026-01-20 20:12:52 +08:00
[Snackbar] Added optional close icon
PiperOrigin-RevId: 845256053
This commit is contained in:
parent
d5934ee5ba
commit
71f014fa41
@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
@ -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>
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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>
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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"/>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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">
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user