Skip to content

Commit

Permalink
[BadgeDrawable] Add padding in between top and bottom edges of badge …
Browse files Browse the repository at this point in the history
…and text

PiperOrigin-RevId: 518370027
  • Loading branch information
imhappi authored and pekingme committed Mar 21, 2023
1 parent 2aa1cf3 commit 8499b83
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 13 deletions.
18 changes: 15 additions & 3 deletions lib/java/com/google/android/material/badge/BadgeDrawable.java
Expand Up @@ -533,7 +533,7 @@ public void clearNumber() {
}

private void onNumberUpdated() {
textDrawableHelper.setTextWidthDirty(true);
textDrawableHelper.setTextSizeDirty(true);
onBadgeShapeAppearanceUpdated();
updateCenterAndBounds();
invalidateSelf();
Expand Down Expand Up @@ -564,7 +564,7 @@ public void setMaxCharacterCount(int maxCharacterCount) {

private void onMaxCharacterCountUpdated() {
updateMaxBadgeNumber();
textDrawableHelper.setTextWidthDirty(true);
textDrawableHelper.setTextSizeDirty(true);
updateCenterAndBounds();
invalidateSelf();
}
Expand Down Expand Up @@ -1017,8 +1017,20 @@ private void calculateCenterAndBounds(@NonNull Rect anchorRect, @NonNull View an
halfBadgeWidth =
Math.round(!hasNumber() ? state.badgeWidth / 2 : state.badgeWithTextWidth / 2);
}
String badgeText = getBadgeText();
// If the badge has a number, we want to make sure that the badge is at least tall/wide
// enough to encompass the text with padding.
if (hasNumber()) {
halfBadgeHeight =
Math.max(
halfBadgeHeight,
textDrawableHelper.getTextHeight(badgeText) / 2f + state.badgeVerticalPadding);

// If the badge has text, it should at least have the same width as it does height
halfBadgeWidth = Math.max(halfBadgeWidth, halfBadgeHeight);
}

if (getNumber() > MAX_CIRCULAR_BADGE_NUMBER_COUNT) {
String badgeText = getBadgeText();
halfBadgeWidth =
Math.max(
halfBadgeWidth,
Expand Down
5 changes: 5 additions & 0 deletions lib/java/com/google/android/material/badge/BadgeState.java
Expand Up @@ -77,6 +77,7 @@ public final class BadgeState {
final float badgeWithTextWidth;
final float badgeWithTextHeight;
final float badgeWidePadding;
final float badgeVerticalPadding;
final int horizontalInset;
final int horizontalInsetWithText;

Expand Down Expand Up @@ -105,6 +106,10 @@ public final class BadgeState {
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()
Expand Down
Expand Up @@ -26,6 +26,8 @@
<attr name="badgeRadius" format="dimension"/>
<!-- Start and end padding for a badge that is oblong due to long text. -->
<attr name="badgeWidePadding" format="dimension"/>
<!-- Top and bottom padding for a badge that is tall due to large text. -->
<attr name="badgeVerticalPadding" format="dimension"/>
<!-- Radius of a badge with text. Deprecated, use badgeWithTextWidth and badgeWithTextHeight
instead. If set, will override badge with text's width/height. -->
<attr name="badgeWithTextRadius" format="dimension"/>
Expand Down
Expand Up @@ -42,4 +42,5 @@

<dimen name="m3_badge_offset">6dp</dimen>
<dimen name="m3_badge_with_text_offset">12dp</dimen>
<dimen name="m3_badge_with_text_vertical_padding">2dp</dimen>
</resources>
Expand Up @@ -68,6 +68,7 @@
<item name="verticalOffsetWithText">@dimen/m3_badge_with_text_offset</item>
<item name="badgeTextAppearance">@macro/m3_comp_badge_large_label_text_type</item>
<item name="badgeWithTextShapeAppearance">@style/ShapeAppearance.M3.Comp.Badge.Shape</item>
<item name="badgeVerticalPadding">@dimen/m3_badge_with_text_vertical_padding</item>
</style>

</resources>
Expand Up @@ -47,7 +47,7 @@ public void onFontRetrieved(@NonNull Typeface typeface, boolean fontResolvedSync
if (fontResolvedSynchronously) {
return;
}
textWidthDirty = true;
textSizeDirty = true;
TextDrawableDelegate textDrawableDelegate = delegate.get();
if (textDrawableDelegate != null) {
textDrawableDelegate.onTextSizeChange();
Expand All @@ -56,7 +56,7 @@ public void onFontRetrieved(@NonNull Typeface typeface, boolean fontResolvedSync

@Override
public void onFontRetrievalFailed(int reason) {
textWidthDirty = true;
textSizeDirty = true;
// Use fallback font.
TextDrawableDelegate textDrawableDelegate = delegate.get();
if (textDrawableDelegate != null) {
Expand All @@ -66,7 +66,8 @@ public void onFontRetrievalFailed(int reason) {
};

private float textWidth;
private boolean textWidthDirty = true;
private float textHeight;
private boolean textSizeDirty = true;
@Nullable private WeakReference<TextDrawableDelegate> delegate = new WeakReference<>(null);
@Nullable private TextAppearance textAppearance;

Expand All @@ -88,21 +89,29 @@ public TextPaint getTextPaint() {
}

public void setTextWidthDirty(boolean dirty) {
textWidthDirty = dirty;
textSizeDirty = dirty;
}

public boolean isTextWidthDirty() {
return textWidthDirty;
return textSizeDirty;
}

public void setTextSizeDirty(boolean dirty) {
textSizeDirty = dirty;
}

private void refreshTextDimens(String text) {
textWidth = calculateTextWidth(text);
textHeight = calculateTextHeight(text);
textSizeDirty = false;
}

/** Returns the visual width of the {@code text} based on its current text appearance. */
public float getTextWidth(String text) {
if (!textWidthDirty) {
if (!textSizeDirty) {
return textWidth;
}

textWidth = calculateTextWidth(text);
textWidthDirty = false;
refreshTextDimens(text);
return textWidth;
}

Expand All @@ -113,6 +122,22 @@ private float calculateTextWidth(@Nullable CharSequence charSequence) {
return textPaint.measureText(charSequence, 0, charSequence.length());
}

/** Returns the visual height of the {@code text} based on its current text appearance. */
public float getTextHeight(@Nullable String text) {
if (!textSizeDirty) {
return textHeight;
}
refreshTextDimens(text);
return textHeight;
}

private float calculateTextHeight(@Nullable String str) {
if (str == null) {
return 0f;
}
return Math.abs(textPaint.getFontMetrics().ascent);
}

/**
* Returns the text appearance.
*
Expand Down Expand Up @@ -141,7 +166,7 @@ public void setTextAppearance(@Nullable TextAppearance textAppearance, Context c
textPaint.drawableState = textDrawableDelegate.getState();
}
textAppearance.updateDrawState(context, textPaint, fontCallback);
textWidthDirty = true;
textSizeDirty = true;
}

TextDrawableDelegate textDrawableDelegate = delegate.get();
Expand Down

0 comments on commit 8499b83

Please sign in to comment.