Skip to content

Commit

Permalink
Remove content layout from card view
Browse files Browse the repository at this point in the history
Due to numerous issues with padding, measure, and crashes with layout bindings. We decided to remove the inner layout.

PiperOrigin-RevId: 271495029
  • Loading branch information
ymarian authored and ldjcmu committed Sep 27, 2019
1 parent 0877072 commit 0f8fa7e
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 141 deletions.
73 changes: 4 additions & 69 deletions lib/java/com/google/android/material/card/MaterialCardView.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import com.google.android.material.R;

import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static com.google.android.material.internal.ThemeEnforcement.createThemedContext;

import android.content.Context;
Expand All @@ -38,11 +37,9 @@
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Checkable;
import android.widget.FrameLayout;
import androidx.cardview.widget.CardView;
import com.google.android.material.internal.ThemeEnforcement;
import com.google.android.material.shape.MaterialShapeDrawable;
Expand Down Expand Up @@ -98,7 +95,6 @@ public interface OnCheckedChangeListener {
private static final String LOG_TAG = "MaterialCardView";

@NonNull private final MaterialCardViewHelper cardViewHelper;
@NonNull private final FrameLayout contentLayout;

/**
* Keep track of when {@link CardView} is done initializing because we don't want to use the
Expand Down Expand Up @@ -128,13 +124,8 @@ public MaterialCardView(Context context, AttributeSet attrs, int defStyleAttr) {
ThemeEnforcement.obtainStyledAttributes(
context, attrs, R.styleable.MaterialCardView, defStyleAttr, DEF_STYLE_RES);

// Add a content view to allow the border to be drawn outside the outline.
contentLayout = new FrameLayout(context);
super.addView(contentLayout, -1, new LayoutParams(MATCH_PARENT, MATCH_PARENT));

// Loads and sets background drawable attributes.
cardViewHelper = new MaterialCardViewHelper(this, attrs, defStyleAttr, DEF_STYLE_RES);
// Get the card background color and content padding that CardView read from the attributes.
cardViewHelper.setCardBackgroundColor(super.getCardBackgroundColor());
cardViewHelper.setUserContentPadding(
super.getContentPaddingLeft(),
Expand All @@ -143,10 +134,7 @@ public MaterialCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super.getContentPaddingBottom());
// Zero out the AppCompat CardView's content padding, the padding will be added to the internal
// contentLayout.
super.setContentPadding(0, 0, 0, 0);
cardViewHelper.loadFromAttributes(attributes);
updateContentLayout();

attributes.recycle();
}

Expand All @@ -166,12 +154,6 @@ public void onInitializeAccessibilityEvent(@NonNull AccessibilityEvent accessibi
accessibilityEvent.setChecked(isChecked());
}

private void updateContentLayout() {
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
cardViewHelper.createOutlineProvider(contentLayout);
}
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Expand Down Expand Up @@ -216,7 +198,6 @@ public ColorStateList getStrokeColorStateList() {
*/
public void setStrokeWidth(@Dimension int strokeWidth) {
cardViewHelper.setStrokeWidth(strokeWidth);
updateContentLayout();
}

/** Returns the stroke width of this card view. */
Expand All @@ -229,7 +210,6 @@ public int getStrokeWidth() {
public void setRadius(float radius) {
super.setRadius(radius);
cardViewHelper.setCornerRadius(radius);
updateContentLayout();
}

@Override
Expand Down Expand Up @@ -267,6 +247,10 @@ public void setContentPadding(int left, int top, int right, int bottom) {
cardViewHelper.setUserContentPadding(left, top, right, bottom);
}

void setAncestorContentPadding(int left, int top, int right, int bottom) {
super.setContentPadding(left, top, right, bottom);
}

@Override
public int getContentPaddingLeft() {
return cardViewHelper.getUserContentPadding().left;
Expand Down Expand Up @@ -303,16 +287,6 @@ public ColorStateList getCardBackgroundColor() {
return cardViewHelper.getCardBackgroundColor();
}

@Override
public void setLayoutParams(ViewGroup.LayoutParams params) {
super.setLayoutParams(params);
LayoutParams layoutParams = (LayoutParams) contentLayout.getLayoutParams();
if (params instanceof LayoutParams) {
layoutParams.gravity = ((LayoutParams) params).gravity;
contentLayout.requestLayout();
}
}

@Override
public void setClickable(boolean clickable) {
super.setClickable(clickable);
Expand Down Expand Up @@ -352,41 +326,6 @@ public void setPreventCornerOverlap(boolean preventCornerOverlap) {
cardViewHelper.updateContentPadding();
}

@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
contentLayout.addView(child, index, params);
}

@Override
public void removeAllViews() {
contentLayout.removeAllViews();
}

@Override
public void removeView(View view) {
contentLayout.removeView(view);
}

@Override
public void removeViewInLayout(View view) {
contentLayout.removeViewInLayout(view);
}

@Override
public void removeViewsInLayout(int start, int count) {
contentLayout.removeViewsInLayout(start, count);
}

@Override
public void removeViewAt(int index) {
contentLayout.removeViewAt(index);
}

@Override
public void removeViews(int start, int count) {
contentLayout.removeViews(start, count);
}

@Override
public void setBackground(Drawable drawable) {
setBackgroundDrawable(drawable);
Expand All @@ -409,10 +348,6 @@ void setBackgroundInternal(Drawable drawable) {
super.setBackgroundDrawable(drawable);
}

void setContentLayoutPadding(int left, int top, int right, int bottom) {
contentLayout.setPadding(left, top, right, bottom);
}

@Override
public boolean isChecked() {
return checked;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@

import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;

import android.annotation.TargetApi;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
Expand All @@ -47,7 +45,6 @@
import androidx.core.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
import androidx.cardview.widget.CardView;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.resources.MaterialResources;
Expand Down Expand Up @@ -92,38 +89,29 @@ class MaterialCardViewHelper {
private static final int CHECKED_ICON_LAYER_INDEX = 2;

@NonNull private final MaterialCardView materialCardView;
private final Rect userContentPadding = new Rect();
@NonNull private final Rect userContentPadding = new Rect();

@NonNull
private final MaterialShapeDrawable bgDrawable; // Will always wrapped in an InsetDrawable
// Will always wrapped in an InsetDrawable
@NonNull private final MaterialShapeDrawable bgDrawable;

@NonNull
private final MaterialShapeDrawable
foregroundContentDrawable; // Will always wrapped in an InsetDrawable
// Will always wrapped in an InsetDrawable
@NonNull private final MaterialShapeDrawable foregroundContentDrawable;

@Dimension
private final int checkedIconMargin;
@Dimension
private final int checkedIconSize;

private MaterialShapeDrawable foregroundShapeDrawable;

@NonNull private final MaterialShapeDrawable drawableInsetByStroke;
private final Rect temporaryBounds = new Rect();
@Dimension private final int checkedIconMargin;
@Dimension private final int checkedIconSize;
@Dimension private int strokeWidth;

// If card is clickable, this is the clickableForegroundDrawable otherwise it draws the stroke.
@Nullable private Drawable fgDrawable;
@Nullable private Drawable checkedIcon;
private ColorStateList rippleColor;
private ColorStateList checkedIconTint;
private ShapeAppearanceModel shapeAppearanceModel; // Shared by background, stroke & ripple

@Nullable private ColorStateList rippleColor;
@Nullable private ColorStateList checkedIconTint;
@Nullable private ShapeAppearanceModel shapeAppearanceModel;
@Nullable private ColorStateList strokeColor;
@Nullable private Drawable rippleDrawable;
@Nullable private LayerDrawable clickableForegroundDrawable;
@Nullable private MaterialShapeDrawable compatRippleDrawable;

@Dimension private int strokeWidth;
@Nullable private MaterialShapeDrawable foregroundShapeDrawable;

private boolean isBackgroundOverwritten = false;
private boolean checkable;
Expand All @@ -144,12 +132,12 @@ public MaterialCardViewHelper(
card.getContext()
.obtainStyledAttributes(attrs, R.styleable.CardView, defStyleAttr, R.style.CardView);
if (cardViewAttributes.hasValue(R.styleable.CardView_cardCornerRadius)) {
// If cardCornerRadius is set, let it override the shape appearance.
shapeAppearanceModelBuilder.setCornerRadius(
cardViewAttributes.getDimension(R.styleable.CardView_cardCornerRadius, 0));
}

foregroundContentDrawable = new MaterialShapeDrawable();
drawableInsetByStroke = new MaterialShapeDrawable();
setShapeAppearanceModel(shapeAppearanceModelBuilder.build());

Resources resources = card.getResources();
Expand All @@ -161,14 +149,14 @@ public MaterialCardViewHelper(
}

void loadFromAttributes(@NonNull TypedArray attributes) {
// If cardCornerRadius is set, let it override the shape appearance.
strokeColor = MaterialResources.getColorStateList(
materialCardView.getContext(),
attributes,
R.styleable.MaterialCardView_strokeColor);
if (strokeColor == null) {
strokeColor = ColorStateList.valueOf(DEFAULT_STROKE_VALUE);
}

strokeWidth = attributes.getDimensionPixelSize(R.styleable.MaterialCardView_strokeWidth, 0);
checkable = attributes.getBoolean(R.styleable.MaterialCardView_android_checkable, false);
materialCardView.setLongClickable(checkable);
Expand All @@ -186,7 +174,6 @@ void loadFromAttributes(@NonNull TypedArray attributes) {
ColorStateList.valueOf(
MaterialColors.getColor(materialCardView, R.attr.colorControlHighlight));
}
refreshDrawableInsetByStroke(shapeAppearanceModel);

ColorStateList foregroundColor =
MaterialResources.getColorStateList(
Expand All @@ -198,7 +185,6 @@ void loadFromAttributes(@NonNull TypedArray attributes) {
foregroundColor == null ? ColorStateList.valueOf(Color.TRANSPARENT) : foregroundColor);

updateRippleColor();

updateElevation();
updateStroke();

Expand Down Expand Up @@ -240,7 +226,6 @@ void setStrokeWidth(@Dimension int strokeWidth) {
return;
}
this.strokeWidth = strokeWidth;
refreshDrawableInsetByStroke(shapeAppearanceModel);
updateStroke();
}

Expand Down Expand Up @@ -288,6 +273,7 @@ void setCornerRadius(float cornerRadius) {
|| shouldAddCornerPaddingInsideCardBackground()) {
updateContentPadding();
}

if (shouldAddCornerPaddingOutsideCardBackground()) {
updateInsets();
}
Expand Down Expand Up @@ -329,35 +315,6 @@ void updateStroke() {
foregroundContentDrawable.setStroke(strokeWidth, strokeColor);
}

@TargetApi(VERSION_CODES.LOLLIPOP)
void createOutlineProvider(@Nullable View contentView) {
if (contentView == null) {
return;
}
// To draw the stroke outside the outline, call {@link View#setClipToOutline} on the child
// rather than on the card view.
materialCardView.setClipToOutline(false);
if (canClipToOutline()) {
contentView.setClipToOutline(true);
contentView.setOutlineProvider(
new ViewOutlineProvider() {
@Override
public void getOutline(@NonNull View view, @NonNull Outline outline) {
temporaryBounds.set(
strokeWidth,
strokeWidth,
view.getWidth() - strokeWidth,
view.getHeight() - strokeWidth);
drawableInsetByStroke.setBounds(temporaryBounds);
drawableInsetByStroke.getOutline(outline);
}
});
} else {
contentView.setClipToOutline(false);
contentView.setOutlineProvider(null);
}
}

/**
* Apply content padding to the intermediate contentLayout. Padding includes the user-specified
* content padding as well as any padding ot prevent corner overlap. The padding is applied to the
Expand All @@ -375,7 +332,8 @@ void updateContentPadding() {
(int)
((includeCornerPadding ? calculateActualCornerPadding() : 0)
- getParentCardViewCalculatedCornerPadding());
materialCardView.setContentLayoutPadding(

materialCardView.setAncestorContentPadding(
userContentPadding.left + contentPaddingOffset,
userContentPadding.top + contentPaddingOffset,
userContentPadding.right + contentPaddingOffset,
Expand Down Expand Up @@ -463,7 +421,6 @@ void forceRippleRedraw() {

void setShapeAppearanceModel(@NonNull ShapeAppearanceModel shapeAppearanceModel) {
this.shapeAppearanceModel = shapeAppearanceModel;
refreshDrawableInsetByStroke(shapeAppearanceModel);
bgDrawable.setShapeAppearanceModel(shapeAppearanceModel);
if (foregroundContentDrawable != null) {
foregroundContentDrawable.setShapeAppearanceModel(shapeAppearanceModel);
Expand All @@ -482,18 +439,6 @@ ShapeAppearanceModel getShapeAppearanceModel() {
return shapeAppearanceModel;
}

private void refreshDrawableInsetByStroke(@NonNull ShapeAppearanceModel shapeAppearanceModel) {
if (drawableInsetByStroke != null) {
drawableInsetByStroke.setShapeAppearanceModel(
adjustedShapeAppearanceModelInsetByStroke(shapeAppearanceModel));
}
}

private ShapeAppearanceModel adjustedShapeAppearanceModelInsetByStroke(
ShapeAppearanceModel shapeAppearanceModel) {
return shapeAppearanceModel.withAdjustedCorners(-strokeWidth);
}

/**
* Attempts to update the {@link InsetDrawable} foreground to use the given {@link Drawable}.
* Changing the Drawable is only available in M+, so earlier versions will create a new
Expand Down

0 comments on commit 0f8fa7e

Please sign in to comment.