Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Badge] Remove BadgeUtils.USE_COMPAT_PARENT #4170

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 4 additions & 77 deletions lib/java/com/google/android/material/badge/BadgeDrawable.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
import androidx.annotation.AttrRes;
import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
Expand Down Expand Up @@ -296,11 +295,6 @@ public void setVisible(boolean visible) {
private void onVisibilityUpdated() {
boolean visible = state.isVisible();
setVisible(visible, /* restart= */ false);
// When hiding a badge in pre-API 18, invalidate the custom parent in order to trigger a draw
// pass to remove this badge from its foreground.
if (BadgeUtils.USE_COMPAT_PARENT && getCustomBadgeParent() != null && !visible) {
((ViewGroup) getCustomBadgeParent().getParent()).invalidate();
}
}

/**
Expand Down Expand Up @@ -402,85 +396,26 @@ public void updateBadgeCoordinates(@NonNull View anchorView) {
* also updates this {@code BadgeDrawable BadgeDrawable's} bounds, because they are dependent on
* the center coordinates.
*
* <p>For pre API-18, if no {@code customBadgeParent} is specified, optionally wrap the anchor in
* a {@code FrameLayout} (if it's not done already) that will be inserted into the anchor's view
* hierarchy and calculate the badge's coordinates the parent {@code FrameLayout} because the
* {@code BadgeDrawable} will be set as the parent's foreground.
*
* @param anchorView This badge's anchor.
* @param customBadgeParent An optional parent view that will set this {@code BadgeDrawable} as
* its foreground.
*/
public void updateBadgeCoordinates(
@NonNull View anchorView, @Nullable FrameLayout customBadgeParent) {
this.anchorViewRef = new WeakReference<>(anchorView);
this.customBadgeParentRef = new WeakReference<>(customBadgeParent);

if (BadgeUtils.USE_COMPAT_PARENT && customBadgeParent == null) {
tryWrapAnchorInCompatParent(anchorView);
} else {
this.customBadgeParentRef = new WeakReference<>(customBadgeParent);
}
if (!BadgeUtils.USE_COMPAT_PARENT) {
updateAnchorParentToNotClip(anchorView);
}
updateAnchorParentToNotClip(anchorView);
updateCenterAndBounds();
invalidateSelf();
}

private boolean isAnchorViewWrappedInCompatParent() {
View customBadgeAnchorParent = getCustomBadgeParent();
return customBadgeAnchorParent != null
&& customBadgeAnchorParent.getId() == R.id.mtrl_anchor_parent;
}

/** Returns a {@link FrameLayout} that will set this {@code BadgeDrawable} as its foreground. */
@Nullable
public FrameLayout getCustomBadgeParent() {
return customBadgeParentRef != null ? customBadgeParentRef.get() : null;
}

/**
* ViewOverlay is not supported below api 18, wrap the anchor view in a {@code FrameLayout} in
* order to support scrolling.
*/
private void tryWrapAnchorInCompatParent(final View anchorView) {
ViewGroup anchorViewParent = (ViewGroup) anchorView.getParent();
if ((anchorViewParent != null && anchorViewParent.getId() == R.id.mtrl_anchor_parent)
|| (customBadgeParentRef != null && customBadgeParentRef.get() == anchorViewParent)) {
return;
}
// Must call this before wrapping the anchor in a FrameLayout.
updateAnchorParentToNotClip(anchorView);

// Create FrameLayout and configure it to wrap the anchor.
final FrameLayout frameLayout = new FrameLayout(anchorView.getContext());
frameLayout.setId(R.id.mtrl_anchor_parent);
MGaetan89 marked this conversation as resolved.
Show resolved Hide resolved
frameLayout.setClipChildren(false);
frameLayout.setClipToPadding(false);
frameLayout.setLayoutParams(anchorView.getLayoutParams());
frameLayout.setMinimumWidth(anchorView.getWidth());
frameLayout.setMinimumHeight(anchorView.getHeight());

int anchorIndex = anchorViewParent.indexOfChild(anchorView);
anchorViewParent.removeViewAt(anchorIndex);
anchorView.setLayoutParams(
new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

frameLayout.addView(anchorView);
anchorViewParent.addView(frameLayout, anchorIndex);
customBadgeParentRef = new WeakReference<>(frameLayout);

// Update the badge's coordinates after the FrameLayout has been added to the view hierarchy and
// has a size.
frameLayout.post(
new Runnable() {
@Override
public void run() {
updateBadgeCoordinates(anchorView, frameLayout);
}
});
}

private static void updateAnchorParentToNotClip(View anchorView) {
ViewGroup anchorViewParent = (ViewGroup) anchorView.getParent();
anchorViewParent.setClipChildren(false);
Expand Down Expand Up @@ -1230,11 +1165,9 @@ private void updateCenterAndBounds() {
anchorView.getDrawingRect(anchorRect);

ViewGroup customBadgeParent = customBadgeParentRef != null ? customBadgeParentRef.get() : null;
if (customBadgeParent != null || BadgeUtils.USE_COMPAT_PARENT) {
if (customBadgeParent != null) {
// Calculates coordinates relative to the parent.
ViewGroup viewGroup =
customBadgeParent == null ? (ViewGroup) anchorView.getParent() : customBadgeParent;
viewGroup.offsetDescendantRectToMyCoords(anchorView, anchorRect);
customBadgeParent.offsetDescendantRectToMyCoords(anchorView, anchorRect);
}

calculateCenterAndBounds(anchorRect, anchorView);
Expand Down Expand Up @@ -1389,10 +1322,6 @@ private void autoAdjustWithinViewBounds(@NonNull View anchorView, @Nullable View
totalAnchorYOffset = anchorView.getY();
totalAnchorXOffset = anchorView.getX();
anchorParent = anchorView.getParent();
} else if (isAnchorViewWrappedInCompatParent()) {
totalAnchorYOffset = ((View) customAnchorParent).getY();
totalAnchorXOffset = ((View) customAnchorParent).getX();
anchorParent = customAnchorParent.getParent();
} else {
totalAnchorYOffset = 0;
totalAnchorXOffset = 0;
Expand Down Expand Up @@ -1446,8 +1375,6 @@ private void autoAdjustWithinGrandparentBounds(@NonNull View anchorView) {
ViewParent anchorParent = null;
if (customAnchor == null) {
anchorParent = anchorView.getParent();
} else if (isAnchorViewWrappedInCompatParent()) {
anchorParent = customAnchor.getParent();
} else {
anchorParent = customAnchor;
}
Expand Down
10 changes: 2 additions & 8 deletions lib/java/com/google/android/material/badge/BadgeUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@
@ExperimentalBadgeUtils
public class BadgeUtils {

public static final boolean USE_COMPAT_PARENT = VERSION.SDK_INT < VERSION_CODES.JELLY_BEAN_MR2;

private static final String LOG_TAG = "BadgeUtils";

private BadgeUtils() {
Expand Down Expand Up @@ -93,11 +91,7 @@ public static void attachBadgeDrawable(
if (badgeDrawable.getCustomBadgeParent() != null) {
badgeDrawable.getCustomBadgeParent().setForeground(badgeDrawable);
} else {
if (USE_COMPAT_PARENT) {
throw new IllegalArgumentException("Trying to reference null customBadgeParent");
} else {
anchor.getOverlay().add(badgeDrawable);
}
anchor.getOverlay().add(badgeDrawable);
}
}

Expand Down Expand Up @@ -182,7 +176,7 @@ public static void detachBadgeDrawable(
if (badgeDrawable == null) {
return;
}
if (USE_COMPAT_PARENT || badgeDrawable.getCustomBadgeParent() != null) {
if (badgeDrawable.getCustomBadgeParent() != null) {
badgeDrawable.getCustomBadgeParent().setForeground(null);
} else {
anchor.getOverlay().remove(badgeDrawable);
Expand Down
22 changes: 0 additions & 22 deletions lib/java/com/google/android/material/badge/res/values/ids.xml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -944,9 +944,6 @@ private void tryRemoveBadgeFromAnchor(@Nullable View anchorView) {

@Nullable
private FrameLayout getCustomParentForBadge(View anchorView) {
if (anchorView == icon) {
return BadgeUtils.USE_COMPAT_PARENT ? ((FrameLayout) icon.getParent()) : null;
}
// TODO(b/138148581): Support displaying a badge on label-only bottom navigation views.
return null;
}
Expand Down
54 changes: 6 additions & 48 deletions lib/java/com/google/android/material/tabs/TabLayout.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
Expand Down Expand Up @@ -2311,12 +2310,6 @@ public Tab setIcon(@Nullable Drawable icon) {
parent.updateTabViews(true);
}
updateView();
if (BadgeUtils.USE_COMPAT_PARENT
&& view.hasBadgeDrawable()
&& view.badgeDrawable.isVisible()) {
// Invalidate the TabView if icon visibility has changed and a badge is displayed.
view.invalidate();
}
return this;
}

Expand Down Expand Up @@ -2421,12 +2414,6 @@ public Tab setTabLabelVisibility(@LabelVisibility int mode) {
parent.updateTabViews(true);
}
this.updateView();
if (BadgeUtils.USE_COMPAT_PARENT
&& view.hasBadgeDrawable()
&& view.badgeDrawable.isVisible()) {
// Invalidate the TabView if label visibility has changed and a badge is displayed.
view.invalidate();
}
return this;
}

Expand Down Expand Up @@ -2851,39 +2838,19 @@ final void update() {
}

private void inflateAndAddDefaultIconView() {
ViewGroup iconViewParent = this;
if (BadgeUtils.USE_COMPAT_PARENT) {
iconViewParent = createPreApi18BadgeAnchorRoot();
addView(iconViewParent, 0);
}
this.iconView =
(ImageView)
LayoutInflater.from(getContext())
.inflate(R.layout.design_layout_tab_icon, iconViewParent, false);
iconViewParent.addView(iconView, 0);
.inflate(R.layout.design_layout_tab_icon, this, false);
addView(iconView, 0);
}

private void inflateAndAddDefaultTextView() {
ViewGroup textViewParent = this;
if (BadgeUtils.USE_COMPAT_PARENT) {
textViewParent = createPreApi18BadgeAnchorRoot();
addView(textViewParent);
}
this.textView =
(TextView)
LayoutInflater.from(getContext())
.inflate(R.layout.design_layout_tab_text, textViewParent, false);
textViewParent.addView(textView);
}

@NonNull
private FrameLayout createPreApi18BadgeAnchorRoot() {
FrameLayout frameLayout = new FrameLayout(getContext());
FrameLayout.LayoutParams layoutparams =
new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
frameLayout.setLayoutParams(layoutparams);
return frameLayout;
.inflate(R.layout.design_layout_tab_text, this, false);
addView(textView);
}

/**
Expand Down Expand Up @@ -2979,8 +2946,7 @@ private void tryAttachBadgeToAnchor(@Nullable View anchorView) {
}
if (anchorView != null) {
clipViewToPaddingForBadge(false);
BadgeUtils.attachBadgeDrawable(
badgeDrawable, anchorView, getCustomParentForBadge(anchorView));
BadgeUtils.attachBadgeDrawable(badgeDrawable, anchorView, null);
badgeAnchorView = anchorView;
}
}
Expand Down Expand Up @@ -3095,22 +3061,14 @@ private void updateTextAndIcon(
private void tryUpdateBadgeDrawableBounds(@NonNull View anchor) {
// Check that this view is the badge's current anchor view.
if (hasBadgeDrawable() && anchor == badgeAnchorView) {
BadgeUtils.setBadgeDrawableBounds(badgeDrawable, anchor, getCustomParentForBadge(anchor));
BadgeUtils.setBadgeDrawableBounds(badgeDrawable, anchor, null);
}
}

private boolean hasBadgeDrawable() {
return badgeDrawable != null;
}

@Nullable
private FrameLayout getCustomParentForBadge(@NonNull View anchor) {
if (anchor != iconView && anchor != textView) {
return null;
}
return BadgeUtils.USE_COMPAT_PARENT ? ((FrameLayout) anchor.getParent()) : null;
}

/**
* Calculates the width of the TabView's content.
*
Expand Down