Skip to content

Commit bd4914d

Browse files
hunterstichymarian
authored andcommitted
[Badge] Support differing offsets for badges with/without text, support badge width and padding in styles.
PiperOrigin-RevId: 372538097
1 parent b503287 commit bd4914d

File tree

3 files changed

+109
-6
lines changed

3 files changed

+109
-6
lines changed

lib/java/com/google/android/material/badge/BadgeDrawable.java

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import androidx.annotation.NonNull;
4848
import androidx.annotation.Nullable;
4949
import androidx.annotation.PluralsRes;
50+
import androidx.annotation.Px;
5051
import androidx.annotation.RestrictTo;
5152
import androidx.annotation.StringRes;
5253
import androidx.annotation.StyleRes;
@@ -175,9 +176,9 @@ public class BadgeDrawable extends Drawable implements TextDrawableDelegate {
175176
@NonNull private final MaterialShapeDrawable shapeDrawable;
176177
@NonNull private final TextDrawableHelper textDrawableHelper;
177178
@NonNull private final Rect badgeBounds;
178-
private final float badgeRadius;
179-
private final float badgeWithTextRadius;
180-
private final float badgeWidePadding;
179+
private float badgeRadius;
180+
private float badgeWithTextRadius;
181+
private float badgeWidePadding;
181182
@NonNull private final SavedState savedState;
182183

183184
private float badgeCenterX;
@@ -216,6 +217,12 @@ public static final class SavedState implements Parcelable {
216217
@Dimension(unit = Dimension.PX)
217218
private int verticalOffset;
218219

220+
@Dimension(unit = Dimension.PX)
221+
private int horizontalOffsetWithText;
222+
223+
@Dimension(unit = Dimension.PX)
224+
private int verticalOffsetWithText;
225+
219226
@Dimension(unit = Dimension.PX)
220227
private int additionalHorizontalOffset;
221228

@@ -247,6 +254,8 @@ protected SavedState(@NonNull Parcel in) {
247254
badgeGravity = in.readInt();
248255
horizontalOffset = in.readInt();
249256
verticalOffset = in.readInt();
257+
horizontalOffsetWithText = in.readInt();
258+
verticalOffsetWithText = in.readInt();
250259
additionalHorizontalOffset = in.readInt();
251260
additionalVerticalOffset = in.readInt();
252261
isVisible = in.readInt() != 0;
@@ -284,6 +293,8 @@ public void writeToParcel(@NonNull Parcel dest, int flags) {
284293
dest.writeInt(badgeGravity);
285294
dest.writeInt(horizontalOffset);
286295
dest.writeInt(verticalOffset);
296+
dest.writeInt(horizontalOffsetWithText);
297+
dest.writeInt(verticalOffsetWithText);
287298
dest.writeInt(additionalHorizontalOffset);
288299
dest.writeInt(additionalVerticalOffset);
289300
dest.writeInt(isVisible ? 1 : 0);
@@ -379,6 +390,9 @@ private void restoreFromSavedState(@NonNull SavedState savedState) {
379390
setHorizontalOffset(savedState.horizontalOffset);
380391
setVerticalOffset(savedState.verticalOffset);
381392

393+
setHorizontalOffsetWithText(savedState.horizontalOffsetWithText);
394+
setVerticalOffsetWithText(savedState.verticalOffsetWithText);
395+
382396
setAdditionalHorizontalOffset(savedState.additionalHorizontalOffset);
383397
setAdditionalVerticalOffset(savedState.additionalVerticalOffset);
384398

@@ -414,6 +428,25 @@ private void loadDefaultStateFromAttributes(
414428
setHorizontalOffset(a.getDimensionPixelOffset(R.styleable.Badge_horizontalOffset, 0));
415429
setVerticalOffset(a.getDimensionPixelOffset(R.styleable.Badge_verticalOffset, 0));
416430

431+
// Set the offsets when the badge has text. Default to using the badge "dot" offsets
432+
// (horizontalOffset and verticalOffset) if there is no offsets defined for badges with text.
433+
setHorizontalOffsetWithText(
434+
a.getDimensionPixelOffset(
435+
R.styleable.Badge_horizontalOffsetWithText, getHorizontalOffset()));
436+
setVerticalOffsetWithText(
437+
a.getDimensionPixelOffset(R.styleable.Badge_verticalOffsetWithText, getVerticalOffset()));
438+
439+
if (a.hasValue(R.styleable.Badge_badgeRadius)) {
440+
badgeRadius = a.getDimension(R.styleable.Badge_badgeRadius, badgeRadius);
441+
}
442+
if (a.hasValue(R.styleable.Badge_badgeWidePadding)) {
443+
badgeWidePadding = a.getDimension(R.styleable.Badge_badgeWidePadding, badgeWidePadding);
444+
}
445+
if (a.hasValue(R.styleable.Badge_badgeWithTextRadius)) {
446+
badgeWithTextRadius =
447+
a.getDimension(R.styleable.Badge_badgeWithTextRadius, badgeWithTextRadius);
448+
}
449+
417450
a.recycle();
418451
}
419452

@@ -827,6 +860,26 @@ public int getHorizontalOffset() {
827860
return savedState.horizontalOffset;
828861
}
829862

863+
/**
864+
* Sets how much (in pixels) to horizontally move this badge towards the center of its anchor
865+
* when this badge has text.
866+
*
867+
* @param px badge's horizontal offset when the badge has text.
868+
*/
869+
public void setHorizontalOffsetWithText(@Px int px) {
870+
savedState.horizontalOffsetWithText = px;
871+
updateCenterAndBounds();
872+
}
873+
874+
/**
875+
* Returns how much (in pixels) this badge is being horizontally offset towards the center of its
876+
* anchor when this badge has text.
877+
*/
878+
@Px
879+
public int getHorizontalOffsetWithText() {
880+
return savedState.horizontalOffsetWithText;
881+
}
882+
830883
/**
831884
* Sets how much (in pixels) more (in addition to {@code savedState.horizontalOffset}) to
832885
* horizontally move this badge towards the center of its anchor. Currently used to adjust the
@@ -859,6 +912,26 @@ public int getVerticalOffset() {
859912
return savedState.verticalOffset;
860913
}
861914

915+
/**
916+
* Sets how much (in pixels) to vertically move this badge towards the center of its anchor when
917+
* this badge has text.
918+
*
919+
* @param px badge's vertical offset when the badge has text.
920+
*/
921+
public void setVerticalOffsetWithText(@Px int px) {
922+
savedState.verticalOffsetWithText = px;
923+
updateCenterAndBounds();
924+
}
925+
926+
/**
927+
* Returns how much (in pixels) this badge is being vertically moved towards the center of its
928+
* anchor when the badge has text.
929+
*/
930+
@Px
931+
public int getVerticalOffsetWithText() {
932+
return savedState.verticalOffsetWithText;
933+
}
934+
862935
/**
863936
* Sets how much (in pixels) more (in addition to {@code savedState.verticalOffset}) to vertically
864937
* move this badge towards the center of its anchor. Currently used to adjust the placement of
@@ -924,9 +997,19 @@ private void updateCenterAndBounds() {
924997
}
925998
}
926999

1000+
private int getTotalVerticalOffsetForState() {
1001+
int vOffset = hasNumber() ? savedState.verticalOffsetWithText : savedState.verticalOffset;
1002+
return vOffset + savedState.additionalVerticalOffset;
1003+
}
1004+
1005+
private int getTotalHorizontalOffsetForState() {
1006+
int hOffset = hasNumber() ? savedState.horizontalOffsetWithText : savedState.horizontalOffset;
1007+
return hOffset + savedState.additionalHorizontalOffset;
1008+
}
1009+
9271010
private void calculateCenterAndBounds(
9281011
@NonNull Context context, @NonNull Rect anchorRect, @NonNull View anchorView) {
929-
int totalVerticalOffset = savedState.verticalOffset + savedState.additionalVerticalOffset;
1012+
int totalVerticalOffset = getTotalVerticalOffsetForState();
9301013
switch (savedState.badgeGravity) {
9311014
case BOTTOM_END:
9321015
case BOTTOM_START:
@@ -958,7 +1041,7 @@ private void calculateCenterAndBounds(
9581041
? R.dimen.mtrl_badge_text_horizontal_edge_offset
9591042
: R.dimen.mtrl_badge_horizontal_edge_offset);
9601043

961-
int totalHorizontalOffset = savedState.horizontalOffset + savedState.additionalHorizontalOffset;
1044+
int totalHorizontalOffset = getTotalHorizontalOffsetForState();
9621045

9631046
// Update the centerX based on the badge width and 'inset' from start or end boundary of anchor.
9641047
switch (savedState.badgeGravity) {

lib/java/com/google/android/material/badge/res/values/attrs.xml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121
<attr name="badgeStyle" format="reference"/>
2222

2323
<declare-styleable name="Badge">
24+
<!-- The radius of a badge without text (a "dot"). -->
25+
<attr name="badgeRadius" format="dimension"/>
26+
<!-- Start and end padding for a badge that is oblong due to long text. -->
27+
<attr name="badgeWidePadding" format="dimension"/>
28+
<!-- Radius of a badge with text. -->
29+
<attr name="badgeWithTextRadius" format="dimension"/>
2430
<attr name="backgroundColor" format="color"/>
2531
<attr name="badgeTextColor" format="color"/>
2632
<attr name="maxCharacterCount" format="integer"/>
@@ -36,9 +42,20 @@
3642
<enum name="BOTTOM_START" value ="8388691"/>
3743
</attr>
3844

39-
<!-- Offset moves the badge towards the center of its anchor. -->
45+
<!-- Offsets the badge horizontally towards the center of its anchor when
46+
the badge doesn't have text (is a "dot"). Defaults to 0. -->
4047
<attr name="horizontalOffset" format="dimension"/>
48+
<!-- Offsets the badge vertically towards the center of its anchor when the
49+
badge doesn't have text (is a "dot"). Defaults to 0. -->
4150
<attr name="verticalOffset" format="dimension"/>
51+
<!-- Offsets the badge horizontally towards the center of its anchor when
52+
the badge has text. If this is not defined, it will default to
53+
horizontalOffset's value. -->
54+
<attr name="horizontalOffsetWithText" format="dimension"/>
55+
<!-- Offsets the badge vertically towards the center of its anchor when the
56+
badge has text. If this is not defined, it will default to
57+
verticalOffset's value. -->
58+
<attr name="verticalOffsetWithText" format="dimension"/>
4259
</declare-styleable>
4360

4461
</resources>

lib/java/com/google/android/material/badge/res/values/styles.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi">
1818

1919
<style name="Widget.MaterialComponents.Badge" parent="android:Widget">
20+
<item name="badgeRadius">@dimen/mtrl_badge_radius</item>
21+
<item name="badgeWidePadding">@dimen/mtrl_badge_long_text_horizontal_padding</item>
22+
<item name="badgeWithTextRadius">@dimen/mtrl_badge_with_text_radius</item>
2023
<item name="backgroundColor">?attr/colorError</item>
2124
<item name="maxCharacterCount">@integer/mtrl_badge_max_character_count</item>
2225
<item name="badgeGravity">TOP_END</item>

0 commit comments

Comments
 (0)