diff --git a/docs/components/BadgeDrawable.md b/docs/components/BadgeDrawable.md index d40d2461a3b..1bad7fd25da 100644 --- a/docs/components/BadgeDrawable.md +++ b/docs/components/BadgeDrawable.md @@ -90,18 +90,20 @@ center, use `setHorizontalOffset(int)` or `setVerticalOffset(int)` ### `BadgeDrawable` Attributes -| Feature | Relevant attributes | -| --------------------- | -----------------------------------------------------------------------------------------------------------------| -| Color | `app:backgroundColor`
`app:badgeTextColor` | -| Width | `app:badgeWidth`
`app:badgeWithTextWidth` | -| Height | `app:badgeHeight`
`app:badgeWithTextHeight` | -| Shape | `app:badgeShapeAppearance`
`app:badgeShapeAppearanceOverlay`
`app:badgeWithTextShapeAppearance`
`app:badgeWithTextShapeAppearanceOverlay` | -| Label | `app:badgeText` (for text)
`app:number` (for numbers) | -| Label Length | `app:maxCharacterCount` | -| Label Text Color | `app:badgeTextColor` | -| Label Text Appearance | `app:badgeTextAppearance` | -| Badge Gravity | `app:badgeGravity` | -| Offset Alignment | `app:offsetAlignmentMode` | +| Feature | Relevant attributes | +|-----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------| +| Color | `app:backgroundColor`
`app:badgeTextColor` | +| Width | `app:badgeWidth`
`app:badgeWithTextWidth` | +| Height | `app:badgeHeight`
`app:badgeWithTextHeight` | +| Shape | `app:badgeShapeAppearance`
`app:badgeShapeAppearanceOverlay`
`app:badgeWithTextShapeAppearance`
`app:badgeWithTextShapeAppearanceOverlay` | +| Label | `app:badgeText` (for text)
`app:number` (for numbers) | +| Label Length | `app:maxCharacterCount` | +| Label Text Color | `app:badgeTextColor` | +| Label Text Appearance | `app:badgeTextAppearance` | +| Badge Gravity | `app:badgeGravity` | +| Offset Alignment | `app:offsetAlignmentMode` | +| Horizontal Padding | `app:badgeWidePadding` | +| Vertical Padding | `app:badgeVerticalPadding` | **Note:** If both `app:badgeText` and `app:number` are specified, the badge label will be `app:badgeText`. diff --git a/lib/java/com/google/android/material/badge/BadgeDrawable.java b/lib/java/com/google/android/material/badge/BadgeDrawable.java index e2cf2ca567a..3b4204491b1 100644 --- a/lib/java/com/google/android/material/badge/BadgeDrawable.java +++ b/lib/java/com/google/android/material/badge/BadgeDrawable.java @@ -783,6 +783,48 @@ private CharSequence getEmptyContentDescription() { return state.getContentDescriptionNumberless(); } + /** + * Sets how much (in pixels) horizontal padding to add to the badge when it has label contents. + * Note that badges have a minimum width as specified by + * com.google.android.material.R.styleable#Badge_badgeWidth. + * + * @param horizontalPadding badge's horizontal padding + * @attr ref com.google.android.material.R.styleable#Badge_badgeWidePadding + */ + public void setHorizontalPadding(@Px int horizontalPadding) { + if (horizontalPadding != state.getBadgeHorizontalPadding()) { + state.setBadgeHorizontalPadding(horizontalPadding); + updateCenterAndBounds(); + } + } + + /** Returns the badge horizontal padding in pixels. */ + @Px + public int getHorizontalPadding() { + return state.getBadgeHorizontalPadding(); + } + + /** + * Sets how much (in pixels) vertical padding to add to the badge when it has label contents. Note + * that badges have a minimum height as specified by + * com.google.android.material.R.styleable#Badge_badgeHeight. + * + * @param verticalPadding badge's vertical padding + * @attr ref com.google.android.material.R.styleable#Badge_badgeVerticalPadding + */ + public void setVerticalPadding(@Px int verticalPadding) { + if (verticalPadding != state.getBadgeVerticalPadding()) { + state.setBadgeVerticalPadding(verticalPadding); + updateCenterAndBounds(); + } + } + + /** Returns the badge vertical padding in pixels. */ + @Px + public int getVerticalPadding() { + return state.getBadgeVerticalPadding(); + } + /** * Sets how much (in pixels) to horizontally move this badge towards the center of its anchor. * @@ -1106,7 +1148,8 @@ private void calculateCenterAndBounds(@NonNull Rect anchorRect, @NonNull View an halfBadgeHeight = Math.max( halfBadgeHeight, - textDrawableHelper.getTextHeight(badgeContent) / 2f + state.badgeVerticalPadding); + textDrawableHelper.getTextHeight(badgeContent) / 2f + + state.getBadgeVerticalPadding()); // If the badge has text, it should at least have the same width as it does height halfBadgeWidth = Math.max(halfBadgeWidth, halfBadgeHeight); @@ -1119,7 +1162,8 @@ private void calculateCenterAndBounds(@NonNull Rect anchorRect, @NonNull View an halfBadgeWidth = Math.max( halfBadgeWidth, - textDrawableHelper.getTextWidth(badgeContent) / 2f + state.badgeWidePadding); + textDrawableHelper.getTextWidth(badgeContent) / 2f + + state.getBadgeHorizontalPadding()); } int totalVerticalOffset = getTotalVerticalOffsetForState(); diff --git a/lib/java/com/google/android/material/badge/BadgeState.java b/lib/java/com/google/android/material/badge/BadgeState.java index 98f45376c6a..c0e17c7257e 100644 --- a/lib/java/com/google/android/material/badge/BadgeState.java +++ b/lib/java/com/google/android/material/badge/BadgeState.java @@ -37,6 +37,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.PluralsRes; +import androidx.annotation.Px; import androidx.annotation.RestrictTo; import androidx.annotation.StringRes; import androidx.annotation.StyleRes; @@ -76,8 +77,6 @@ public final class BadgeState { final float badgeHeight; final float badgeWithTextWidth; final float badgeWithTextHeight; - final float badgeWidePadding; - final float badgeVerticalPadding; final int horizontalInset; final int horizontalInsetWithText; @@ -102,14 +101,7 @@ public final class BadgeState { Resources res = context.getResources(); badgeRadius = a.getDimensionPixelSize(R.styleable.Badge_badgeRadius, BADGE_RADIUS_NOT_SPECIFIED); - badgeWidePadding = - a.getDimensionPixelSize( - R.styleable.Badge_badgeWidePadding, - res.getDimensionPixelSize(R.dimen.mtrl_badge_long_text_horizontal_padding)); - badgeVerticalPadding = - a.getDimension( - R.styleable.Badge_badgeVerticalPadding, - res.getDimension(R.dimen.m3_badge_with_text_vertical_padding)); + horizontalInset = context .getResources() @@ -236,6 +228,19 @@ public final class BadgeState { ? a.getInt(R.styleable.Badge_badgeGravity, TOP_END) : storedState.badgeGravity; + currentState.badgeHorizontalPadding = + storedState.badgeHorizontalPadding == null + ? a.getDimensionPixelSize( + R.styleable.Badge_badgeWidePadding, + res.getDimensionPixelSize(R.dimen.mtrl_badge_long_text_horizontal_padding)) + : storedState.badgeHorizontalPadding; + currentState.badgeVerticalPadding = + storedState.badgeVerticalPadding == null + ? a.getDimensionPixelSize( + R.styleable.Badge_badgeVerticalPadding, + res.getDimensionPixelSize(R.dimen.m3_badge_with_text_vertical_padding)) + : storedState.badgeVerticalPadding; + currentState.horizontalOffsetWithoutText = storedState.horizontalOffsetWithoutText == null ? a.getDimensionPixelOffset(R.styleable.Badge_horizontalOffset, 0) @@ -442,6 +447,26 @@ void setBadgeGravity(@BadgeGravity int badgeGravity) { currentState.badgeGravity = badgeGravity; } + @Px + int getBadgeHorizontalPadding() { + return currentState.badgeHorizontalPadding; + } + + void setBadgeHorizontalPadding(@Px int horizontalPadding) { + overridingState.badgeHorizontalPadding = horizontalPadding; + currentState.badgeHorizontalPadding = horizontalPadding; + } + + @Px + int getBadgeVerticalPadding() { + return currentState.badgeVerticalPadding; + } + + void setBadgeVerticalPadding(@Px int verticalPadding) { + overridingState.badgeVerticalPadding = verticalPadding; + currentState.badgeVerticalPadding = verticalPadding; + } + @Dimension(unit = Dimension.PX) int getHorizontalOffsetWithoutText() { return currentState.horizontalOffsetWithoutText; @@ -591,6 +616,10 @@ public static final class State implements Parcelable { @BadgeGravity private Integer badgeGravity; private Boolean isVisible = true; + @Px private Integer badgeHorizontalPadding; + + @Px private Integer badgeVerticalPadding; + @Dimension(unit = Dimension.PX) private Integer horizontalOffsetWithoutText; @@ -628,6 +657,8 @@ public State() {} contentDescriptionNumberless = in.readString(); contentDescriptionQuantityStrings = in.readInt(); badgeGravity = (Integer) in.readSerializable(); + badgeHorizontalPadding = (Integer) in.readSerializable(); + badgeVerticalPadding = (Integer) in.readSerializable(); horizontalOffsetWithoutText = (Integer) in.readSerializable(); verticalOffsetWithoutText = (Integer) in.readSerializable(); horizontalOffsetWithText = (Integer) in.readSerializable(); @@ -678,6 +709,8 @@ public void writeToParcel(@NonNull Parcel dest, int flags) { contentDescriptionNumberless != null ? contentDescriptionNumberless.toString() : null); dest.writeInt(contentDescriptionQuantityStrings); dest.writeSerializable(badgeGravity); + dest.writeSerializable(badgeHorizontalPadding); + dest.writeSerializable(badgeVerticalPadding); dest.writeSerializable(horizontalOffsetWithoutText); dest.writeSerializable(verticalOffsetWithoutText); dest.writeSerializable(horizontalOffsetWithText); diff --git a/lib/java/com/google/android/material/badge/res-public/values/public.xml b/lib/java/com/google/android/material/badge/res-public/values/public.xml index 4b58112f6f0..d31a0bbad06 100644 --- a/lib/java/com/google/android/material/badge/res-public/values/public.xml +++ b/lib/java/com/google/android/material/badge/res-public/values/public.xml @@ -23,6 +23,8 @@ + + diff --git a/lib/javatests/com/google/android/material/badge/BadgeDrawableTest.java b/lib/javatests/com/google/android/material/badge/BadgeDrawableTest.java index c0da0461a1e..ea476b0718c 100644 --- a/lib/javatests/com/google/android/material/badge/BadgeDrawableTest.java +++ b/lib/javatests/com/google/android/material/badge/BadgeDrawableTest.java @@ -50,6 +50,9 @@ public class BadgeDrawableTest { private static final int TEST_BADGE_HORIZONTAL_OFFSET = 10; private static final int TEST_BADGE_VERTICAL_OFFSET = 5; + private static final int TEST_BADGE_HORIZONTAL_PADDING = 10; + private static final int TEST_BADGE_VERTICAL_PADDING = 10; + private final Context context = ApplicationProvider.getApplicationContext(); @Before @@ -70,6 +73,9 @@ public void testSavedState() { badgeDrawable.setNumber(TEST_BADGE_NUMBER); badgeDrawable.setBadgeGravity(BadgeDrawable.TOP_START); + badgeDrawable.setHorizontalPadding(TEST_BADGE_HORIZONTAL_PADDING); + badgeDrawable.setVerticalPadding(TEST_BADGE_VERTICAL_PADDING); + badgeDrawable.setHorizontalOffset(TEST_BADGE_HORIZONTAL_OFFSET); badgeDrawable.setVerticalOffset(TEST_BADGE_VERTICAL_OFFSET); @@ -104,6 +110,9 @@ public void testSavedState() { assertThat(restoredBadgeDrawable.getAlpha()).isEqualTo(255); assertThat(restoredBadgeDrawable.getMaxCharacterCount()).isEqualTo(4); assertThat(restoredBadgeDrawable.getBadgeGravity()).isEqualTo(BadgeDrawable.TOP_START); + // badge padding + assertThat(restoredBadgeDrawable.getHorizontalPadding()).isEqualTo(TEST_BADGE_HORIZONTAL_PADDING); + assertThat(restoredBadgeDrawable.getVerticalPadding()).isEqualTo(TEST_BADGE_VERTICAL_PADDING); // badge offsets assertThat(restoredBadgeDrawable.getHorizontalOffset()).isEqualTo(TEST_BADGE_HORIZONTAL_OFFSET); assertThat(restoredBadgeDrawable.getVerticalOffset()).isEqualTo(TEST_BADGE_VERTICAL_OFFSET);