Skip to content

Commit

Permalink
[Badge] Add badgeFixedEdge attribute to BadgeDrawable.
Browse files Browse the repository at this point in the history
By default, badges are fixed at their start edge (meaning they grow towards the end). If using a badgeGravity corresponding to the start, you will need to update to badgeFixedEdge=end to maintain the same grow towards the start behavior as before

PiperOrigin-RevId: 632236586
  • Loading branch information
imhappi authored and dsn5ft committed May 13, 2024
1 parent fdc7472 commit 9451acd
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 7 deletions.
2 changes: 2 additions & 0 deletions docs/components/BadgeDrawable.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ badge is not clipped if there is enough space.
| Horizontal Padding | `app:badgeWidePadding` |
| Vertical Padding | `app:badgeVerticalPadding` |
| Large Font Vertical Offset| `app:largeFontVerticalOffsetAdjustment` |
| Badge Fixed Edge | `app:badgeFixedEdge` |


**Note:** If both `app:badgeText` and `app:number` are specified, the badge label will be `app:badgeText`.

Expand Down
51 changes: 44 additions & 7 deletions lib/java/com/google/android/material/badge/BadgeDrawable.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
import androidx.annotation.StringRes;
import androidx.annotation.StyleRes;
import androidx.annotation.XmlRes;
import androidx.core.view.ViewCompat;
import com.google.android.material.animation.AnimationUtils;
import com.google.android.material.internal.TextDrawableHelper;
import com.google.android.material.internal.TextDrawableHelper.TextDrawableDelegate;
Expand Down Expand Up @@ -204,6 +203,25 @@ public class BadgeDrawable extends Drawable implements TextDrawableDelegate {
@Retention(RetentionPolicy.SOURCE)
@interface OffsetAlignmentMode {}

/**
* The badge's edge is fixed at the start and grows towards the end.
*/
public static final int BADGE_FIXED_EDGE_START = 0;

/**
* The badge's edge is fixed at the end and grows towards the start.
*/
public static final int BADGE_FIXED_EDGE_END = 1;

/**
* Determines which edge of the badge is fixed, and which direction it grows towards.
*
* @hide
*/
@IntDef({BADGE_FIXED_EDGE_START, BADGE_FIXED_EDGE_END})
@Retention(RetentionPolicy.SOURCE)
@interface BadgeFixedEdge {}

/** A value to indicate that a badge radius has not been specified. */
static final int BADGE_RADIUS_NOT_SPECIFIED = -1;

Expand Down Expand Up @@ -285,6 +303,19 @@ private void onVisibilityUpdated() {
}
}

/**
* Sets this badge's fixed edge. The badge does not grow in the direction of the fixed edge.
*
* @param fixedEdge Constant representing a {@link BadgeFixedEdge} value. The two options are
* {@link #BADGE_FIXED_EDGE_START} and {@link #BADGE_FIXED_EDGE_END}.
*/
public void setBadgeFixedEdge(@BadgeFixedEdge int fixedEdge) {
if (state.badgeFixedEdge != fixedEdge) {
state.badgeFixedEdge = fixedEdge;
updateCenterAndBounds();
}
}

private void restoreState() {
onBadgeShapeAppearanceUpdated();
onBadgeTextAppearanceUpdated();
Expand Down Expand Up @@ -1310,18 +1341,24 @@ private void calculateCenterAndBounds(@NonNull Rect anchorRect, @NonNull View an
switch (state.getBadgeGravity()) {
case BOTTOM_START:
case TOP_START:
badgeCenterX =
ViewCompat.getLayoutDirection(anchorView) == View.LAYOUT_DIRECTION_LTR
badgeCenterX = state.badgeFixedEdge == BADGE_FIXED_EDGE_START
? (anchorView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR
? anchorRect.left + halfBadgeWidth - (halfBadgeHeight * 2 - totalHorizontalOffset)
: anchorRect.right - halfBadgeWidth + (halfBadgeHeight * 2 - totalHorizontalOffset))
: (anchorView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR
? anchorRect.left - halfBadgeWidth + totalHorizontalOffset
: anchorRect.right + halfBadgeWidth - totalHorizontalOffset;
: anchorRect.right + halfBadgeWidth - totalHorizontalOffset);
break;
case BOTTOM_END:
case TOP_END:
default:
badgeCenterX =
ViewCompat.getLayoutDirection(anchorView) == View.LAYOUT_DIRECTION_LTR
badgeCenterX = state.badgeFixedEdge == BADGE_FIXED_EDGE_START
? (anchorView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR
? anchorRect.right + halfBadgeWidth - totalHorizontalOffset
: anchorRect.left - halfBadgeWidth + totalHorizontalOffset;
: anchorRect.left - halfBadgeWidth + totalHorizontalOffset)
: (anchorView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR
? anchorRect.right - halfBadgeWidth + (halfBadgeHeight * 2 - totalHorizontalOffset)
: anchorRect.left + halfBadgeWidth - (halfBadgeHeight * 2 - totalHorizontalOffset));
break;
}

Expand Down
12 changes: 12 additions & 0 deletions lib/java/com/google/android/material/badge/BadgeState.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import static com.google.android.material.badge.BadgeDrawable.BADGE_CONTENT_NOT_TRUNCATED;
import static com.google.android.material.badge.BadgeDrawable.BADGE_FIXED_EDGE_START;
import static com.google.android.material.badge.BadgeDrawable.BADGE_RADIUS_NOT_SPECIFIED;
import static com.google.android.material.badge.BadgeDrawable.OFFSET_ALIGNMENT_MODE_LEGACY;
import static com.google.android.material.badge.BadgeDrawable.TOP_END;
Expand All @@ -44,6 +45,7 @@
import androidx.annotation.StyleRes;
import androidx.annotation.StyleableRes;
import androidx.annotation.XmlRes;
import com.google.android.material.badge.BadgeDrawable.BadgeFixedEdge;
import com.google.android.material.badge.BadgeDrawable.BadgeGravity;
import com.google.android.material.badge.BadgeDrawable.OffsetAlignmentMode;
import com.google.android.material.drawable.DrawableUtils;
Expand Down Expand Up @@ -79,6 +81,9 @@ public final class BadgeState {
@OffsetAlignmentMode
int offsetAlignmentMode;

@BadgeFixedEdge
int badgeFixedEdge;

BadgeState(
Context context,
@XmlRes int badgeResId,
Expand Down Expand Up @@ -126,6 +131,9 @@ public final class BadgeState {
offsetAlignmentMode =
a.getInt(R.styleable.Badge_offsetAlignmentMode, OFFSET_ALIGNMENT_MODE_LEGACY);

badgeFixedEdge =
a.getInt(R.styleable.Badge_badgeFixedEdge, BADGE_FIXED_EDGE_START);

currentState.alpha = storedState.alpha == State.NOT_SET ? 255 : storedState.alpha;

// Only set the badge number if it exists in the style.
Expand Down Expand Up @@ -687,6 +695,8 @@ public static final class State implements Parcelable {

private Boolean autoAdjustToWithinGrandparentBounds;

@BadgeFixedEdge private Integer badgeFixedEdge;

public State() {}

State(@NonNull Parcel in) {
Expand Down Expand Up @@ -719,6 +729,7 @@ public State() {}
isVisible = (Boolean) in.readSerializable();
numberLocale = (Locale) in.readSerializable();
autoAdjustToWithinGrandparentBounds = (Boolean) in.readSerializable();
badgeFixedEdge = (Integer) in.readSerializable();
}

public static final Creator<State> CREATOR =
Expand Down Expand Up @@ -774,6 +785,7 @@ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeSerializable(isVisible);
dest.writeSerializable(numberLocale);
dest.writeSerializable(autoAdjustToWithinGrandparentBounds);
dest.writeSerializable(badgeFixedEdge);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<public name="badgeShapeAppearance" type="attr"/>
<public name="badgeWithTextShapeAppearance" type="attr"/>
<public name="badgeShapeAppearanceOverlay" type="attr"/>
<public name="badgeFixedEdge" type="attr"/>
<!-- Deprecated. Badges are automatically moved to within first ancestor
that clips its children. -->
<public name="autoAdjustToWithinGrandparentBounds" type="attr"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@
grandparent's bounds. Deprecated, badges are now automatically moved to
within the first ancestor that clips its children. -->
<attr name="autoAdjustToWithinGrandparentBounds" format="boolean"/>
<!-- The edge of the badge that is fixed and does not grow along with the
badge.-->
<attr name="badgeFixedEdge">
<!-- The start of the badge is fixed and it grows towards the end. -->
<enum name="start" value="0"/>
<!-- The end of the badge is fixed and it grows towards the start. -->
<enum name="end" value="1"/>
</attr>
</declare-styleable>

</resources>

0 comments on commit 9451acd

Please sign in to comment.