/** * Updates the overlay-color rounding of the parent's child drawable. * * <ul> * <li>If rounding mode is OVERLAY_COLOR and the child is not a RoundedCornersDrawable, a new * RoundedCornersDrawable is created and the child gets wrapped with it. * <li>If rounding mode is OVERLAY_COLOR and the child is already wrapped with a * RoundedCornersDrawable, its rounding parameters are updated. * <li>If rounding mode is not OVERLAY_COLOR and the child is wrapped with a * RoundedCornersDrawable, the rounded drawable gets removed and its child gets attached * directly to the parent. * </ul> */ static void updateOverlayColorRounding( DrawableParent parent, @Nullable RoundingParams roundingParams) { Drawable child = parent.getDrawable(); if (roundingParams != null && roundingParams.getRoundingMethod() == RoundingParams.RoundingMethod.OVERLAY_COLOR) { // Overlay rounding requested - either update the overlay params or add a new // drawable that will do the requested rounding. if (child instanceof RoundedCornersDrawable) { RoundedCornersDrawable roundedCornersDrawable = (RoundedCornersDrawable) child; applyRoundingParams(roundedCornersDrawable, roundingParams); roundedCornersDrawable.setOverlayColor(roundingParams.getOverlayColor()); } else { // Important: remove the child before wrapping it with a new parent! child = parent.setDrawable(sEmptyDrawable); child = maybeWrapWithRoundedOverlayColor(child, roundingParams); parent.setDrawable(child); } } else if (child instanceof RoundedCornersDrawable) { // Overlay rounding no longer required so remove drawable that was doing the rounding. RoundedCornersDrawable roundedCornersDrawable = (RoundedCornersDrawable) child; // Important: remove the child before wrapping it with a new parent! child = roundedCornersDrawable.setCurrent(sEmptyDrawable); parent.setDrawable(child); // roundedCornersDrawable is removed and will get garbage collected, clear the child callback sEmptyDrawable.setCallback(null); } }
/** Wraps the parent's child with a ScaleTypeDrawable. */ static ScaleTypeDrawable wrapChildWithScaleType(DrawableParent parent, ScaleType scaleType) { Drawable child = parent.setDrawable(sEmptyDrawable); child = maybeWrapWithScaleType(child, scaleType); parent.setDrawable(child); Preconditions.checkNotNull(child, "Parent has no child drawable!"); return (ScaleTypeDrawable) child; }
/** * Applies rounding on the drawable's leaf. * * <p>Currently only {@link BitmapDrawable} or {@link ColorDrawable} leafs can be rounded. * * <p>If the leaf cannot be rounded, or the rounding params do not specify BITMAP_ONLY mode, the * given drawable is returned without being rounded. * * <p>If the given drawable is a leaf itself, and it can be rounded, then the rounded drawable is * returned. * * <p>If the given drawable is not a leaf, and its leaf can be rounded, the leaf gets rounded, and * the original drawable is returned. * * @return the rounded drawable, or the original drawable if the rounding didn't take place or it * took place on a drawable's child */ static Drawable maybeApplyLeafRounding( @Nullable Drawable drawable, @Nullable RoundingParams roundingParams, Resources resources) { if (drawable == null || roundingParams == null || roundingParams.getRoundingMethod() != RoundingParams.RoundingMethod.BITMAP_ONLY) { return drawable; } if (drawable instanceof ForwardingDrawable) { DrawableParent parent = findDrawableParentForLeaf((ForwardingDrawable) drawable); Drawable child = parent.setDrawable(sEmptyDrawable); child = applyLeafRounding(child, roundingParams, resources); parent.setDrawable(child); return drawable; } else { return applyLeafRounding(drawable, roundingParams, resources); } }
/** Finds the immediate parent of a leaf drawable. */ static DrawableParent findDrawableParentForLeaf(DrawableParent parent) { while (true) { Drawable child = parent.getDrawable(); if (child == parent || !(child instanceof DrawableParent)) { break; } parent = (DrawableParent) child; } return parent; }
/** * Updates the leaf rounding of the parent's child drawable. * * <ul> * <li>If rounding mode is BITMAP_ONLY and the child is not a rounded drawable, it gets rounded * with a new rounded drawable. * <li>If rounding mode is BITMAP_ONLY and the child is already rounded, its rounding parameters * are updated. * <li>If rounding mode is not BITMAP_ONLY and the child is rounded, its rounding parameters are * reset so that no rounding occurs. * </ul> */ static void updateLeafRounding( DrawableParent parent, @Nullable RoundingParams roundingParams, Resources resources) { parent = findDrawableParentForLeaf(parent); Drawable child = parent.getDrawable(); if (roundingParams != null && roundingParams.getRoundingMethod() == RoundingParams.RoundingMethod.BITMAP_ONLY) { // Leaf rounding requested - either update the params or wrap the current drawable in a // drawable that will round it. if (child instanceof Rounded) { Rounded rounded = (Rounded) child; applyRoundingParams(rounded, roundingParams); } else if (child != null) { // Important: remove the child before wrapping it with a new parent! parent.setDrawable(sEmptyDrawable); Drawable rounded = applyLeafRounding(child, roundingParams, resources); parent.setDrawable(rounded); } } else if (child instanceof Rounded) { // No rounding requested - reset rounding params so no rounding occurs. resetRoundingParams((Rounded) child); } }