Skip to content
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
72 changes: 72 additions & 0 deletions lib/java/com/google/android/material/card/MaterialCardView.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import android.graphics.drawable.Drawable;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import androidx.annotation.IntDef;
import androidx.appcompat.content.res.AppCompatResources;
import android.util.AttributeSet;
import android.util.Log;
Expand All @@ -47,6 +48,8 @@
import com.google.android.material.shape.MaterialShapeUtils;
import com.google.android.material.shape.ShapeAppearanceModel;
import com.google.android.material.shape.Shapeable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
* Provides a Material card.
Expand Down Expand Up @@ -93,6 +96,49 @@ public interface OnCheckedChangeListener {
private static final String LOG_TAG = "MaterialCardView";
private static final String ACCESSIBILITY_CLASS_NAME = "androidx.cardview.widget.CardView";

/**
* Gravity used to position the checked icon at the top|start of the Card.
*
* @see #setCheckedIconGravity(int)
* @see #getCheckedIconGravity()
*/
public static final int CHECKED_ICON_GRAVITY_TOP_START = 0x1;

/**
* Gravity used to position the checked icon at the bottom|start of the Card.
*
* @see #setCheckedIconGravity(int)
* @see #getCheckedIconGravity()
*/
public static final int CHECKED_ICON_GRAVITY_BOTTOM_START = 0x2;

/**
* Gravity used to position the checked icon at the top|end of the Card.
*
* @see #setCheckedIconGravity(int)
* @see #getCheckedIconGravity()
*/
public static final int CHECKED_ICON_GRAVITY_TOP_END = 0x3;

/**
* Gravity used to position the checked icon at the bottom|end of the Card.
*
* @see #setCheckedIconGravity(int)
* @see #getCheckedIconGravity()
*/
public static final int CHECKED_ICON_GRAVITY_BOTTOM_END = 0x4;

/** Positions the icon can be set to. */
@IntDef({
CHECKED_ICON_GRAVITY_TOP_START,
CHECKED_ICON_GRAVITY_BOTTOM_START,
CHECKED_ICON_GRAVITY_TOP_END,
CHECKED_ICON_GRAVITY_BOTTOM_END
})
Comment on lines +132 to +137

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is better to have both the vertical and horizontal gravity not the mixture of both and also center alignment would be helpful

@Retention(RetentionPolicy.SOURCE)
public @interface CheckedIconGravity{}


@NonNull private final MaterialCardViewHelper cardViewHelper;

/**
Expand Down Expand Up @@ -582,4 +628,30 @@ private void forceRippleRedrawIfNeeded() {
cardViewHelper.forceRippleRedraw();
}
}

/**
* Gets the checked icon gravity for this card
*
* @return Checked Icon gravity of the card.
* @attr ref com.google.android.material.R.styleable#MaterialCard_checkedIconGravity
* @see #setCheckedIconGravity(int)
*/
@CheckedIconGravity
public int getCheckedIconGravity() {
return cardViewHelper.getCheckedIconGravity();
}

/**
* Sets the checked icon gravity for this card
*
* @attr ref com.google.android.material.R.styleable#MaterialCard_checkedIconGravity
* @param checkedIconGravity checked icon gravity for this card
* @see #getCheckedIconGravity()
*/
public void setCheckedIconGravity(@CheckedIconGravity int checkedIconGravity) {
if (cardViewHelper.getCheckedIconGravity() != checkedIconGravity) {
cardViewHelper.setCheckedIconGravity(checkedIconGravity);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
import com.google.android.material.R;

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

import static com.google.android.material.card.MaterialCardView.CHECKED_ICON_GRAVITY_BOTTOM_END;
import static com.google.android.material.card.MaterialCardView.CHECKED_ICON_GRAVITY_BOTTOM_START;
import static com.google.android.material.card.MaterialCardView.CHECKED_ICON_GRAVITY_TOP_END;
import static com.google.android.material.card.MaterialCardView.CHECKED_ICON_GRAVITY_TOP_START;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
Expand All @@ -46,6 +49,7 @@
import androidx.annotation.RestrictTo;
import androidx.annotation.StyleRes;
import androidx.cardview.widget.CardView;
import com.google.android.material.card.MaterialCardView.CheckedIconGravity;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.resources.MaterialResources;
import com.google.android.material.ripple.RippleUtils;
Expand Down Expand Up @@ -99,6 +103,7 @@ class MaterialCardViewHelper {

@Dimension private final int checkedIconMargin;
@Dimension private final int checkedIconSize;
@CheckedIconGravity private int checkedIconGravity;
@Dimension private int strokeWidth;

// If card is clickable, this is the clickableForegroundDrawable otherwise it draws the stroke.
Expand Down Expand Up @@ -165,6 +170,8 @@ void loadFromAttributes(@NonNull TypedArray attributes) {
setCheckedIcon(
MaterialResources.getDrawable(
materialCardView.getContext(), attributes, R.styleable.MaterialCardView_checkedIcon));
checkedIconGravity = attributes.getInteger(
R.styleable.MaterialCardView_checkedIconGravity, CHECKED_ICON_GRAVITY_TOP_END);

rippleColor =
MaterialResources.getColorStateList(
Expand Down Expand Up @@ -399,15 +406,18 @@ void setCheckedIcon(@Nullable Drawable checkedIcon) {

void onMeasure(int measuredWidth, int measuredHeight) {
if (clickableForegroundDrawable != null) {
int left = measuredWidth - checkedIconMargin - checkedIconSize;
int bottom = measuredHeight - checkedIconMargin - checkedIconSize;
int left = isCheckedIconEnd() ? measuredWidth - checkedIconMargin - checkedIconSize : checkedIconMargin;
int bottom = isCheckedIconBottom() ? checkedIconMargin : measuredHeight - checkedIconMargin - checkedIconSize;

boolean isPreLollipop = VERSION.SDK_INT < VERSION_CODES.LOLLIPOP;
if (isPreLollipop || materialCardView.getUseCompatPadding()) {
bottom -= (int) Math.ceil(2f * calculateVerticalBackgroundPadding());
left -= (int) Math.ceil(2f * calculateHorizontalBackgroundPadding());
}

int right = checkedIconMargin;
int right = isCheckedIconEnd() ? checkedIconMargin : measuredWidth - checkedIconMargin - checkedIconSize;
int top = isCheckedIconBottom() ? measuredHeight - checkedIconMargin - checkedIconSize : checkedIconMargin;

if (ViewCompat.getLayoutDirection(materialCardView) == ViewCompat.LAYOUT_DIRECTION_RTL) {
// swap left and right
int tmp = right;
Expand All @@ -416,7 +426,7 @@ void onMeasure(int measuredWidth, int measuredHeight) {
}

clickableForegroundDrawable.setLayerInset(
CHECKED_ICON_LAYER_INDEX, left, checkedIconMargin /* top */, right, bottom);
CHECKED_ICON_LAYER_INDEX, left, top /* top */, right, bottom);
}
}

Expand Down Expand Up @@ -646,4 +656,29 @@ private Drawable createCheckedIconLayer() {
private MaterialShapeDrawable createForegroundShapeDrawable() {
return new MaterialShapeDrawable(shapeAppearanceModel);
}

@CheckedIconGravity
int getCheckedIconGravity() {
return checkedIconGravity;
}

void setCheckedIconGravity(@CheckedIconGravity int checkedIconGravity) {
this.checkedIconGravity = checkedIconGravity;
}

private boolean isCheckedIconStart() {
return checkedIconGravity == CHECKED_ICON_GRAVITY_TOP_START || checkedIconGravity == CHECKED_ICON_GRAVITY_BOTTOM_START;
}

private boolean isCheckedIconEnd() {
return checkedIconGravity == CHECKED_ICON_GRAVITY_TOP_END || checkedIconGravity == CHECKED_ICON_GRAVITY_BOTTOM_END;
}

private boolean isCheckedIconTop() {
return checkedIconGravity == CHECKED_ICON_GRAVITY_TOP_START || checkedIconGravity == CHECKED_ICON_GRAVITY_TOP_END;
}

private boolean isCheckedIconBottom() {
return checkedIconGravity == CHECKED_ICON_GRAVITY_BOTTOM_START || checkedIconGravity == CHECKED_ICON_GRAVITY_BOTTOM_END;
}
}
11 changes: 11 additions & 0 deletions lib/java/com/google/android/material/card/res/values/attrs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@
<attr name="checkedIcon"/>
<!-- Tint color for the checked icon. -->
<attr name="checkedIconTint"/>
<!-- Specifies how the checked icon should be positioned. -->
<attr name="checkedIconGravity">
<!-- Push icon to the top|start of the card. -->
<flag name="TOP_START" value="0x1"/>
<!-- Push icon to the bottom|start of the card. -->
<flag name="BOTTOM_START" value="0x2"/>
<!-- Push icon to the top|end of the card. -->
<flag name="TOP_END" value="0x3"/>
<!-- Push icon to the bottom|end of the card. -->
<flag name="BOTTOM_END" value="0x4"/>
</attr>
<!-- Ripple color for the Card. -->
<attr name="rippleColor"/>
<!-- State when a Card is being dragged. -->
Expand Down