diff --git a/docs/components/Card.md b/docs/components/Card.md
index 6c28e7ed700..cc9c8603234 100644
--- a/docs/components/Card.md
+++ b/docs/components/Card.md
@@ -380,13 +380,14 @@ border, regardless of the `app:strokeWidth` value.
#### Checked icon attributes
-Element | Attribute | Related method(s) | Default value
-------------- | ------------------- | ------------------------------------------------------------------------------------ | -------------
-**Icon** | `checkedIcon` | `setCheckedIcon`
`setCheckedIconResource`
`getCheckedIcon` | [`@drawable/ic_mtrl_checked_circle.xml`](https://github.com/material-components/material-components-android/tree/master/lib/java/com/google/android/material/resources/res/drawable/ic_mtrl_checked_circle.xml)
-**Color** | `checkedIconTint` | `setCheckedIconTint`
`getCheckedIconTint` | `?attr/colorOutline` (unchecked)
`?attr/colorSecondary` (checked)
-**Checkable** | `android:checkable` | `setCheckable`
`isCheckable` | `false`
-**Size** | `checkedIconSize` | `setCheckedIconSize`
`setCheckedIconSizeResource`
`getCheckedIconSize` | `24dp`
-**Margin** | `checkedIconMargin` | `setCheckedIconMargin`
`setCheckedIconMarginResource`
`getCheckedIconMargin` | `8dp`
+Element | Attribute | Related method(s) | Default value
+------------- | -------------------- | ------------------------------------------------------------------------------------ | -------------
+**Icon** | `checkedIcon` | `setCheckedIcon`
`setCheckedIconResource`
`getCheckedIcon` | [`@drawable/ic_mtrl_checked_circle.xml`](https://github.com/material-components/material-components-android/tree/master/lib/java/com/google/android/material/resources/res/drawable/ic_mtrl_checked_circle.xml)
+**Color** | `checkedIconTint` | `setCheckedIconTint`
`getCheckedIconTint` | `?attr/colorOutline` (unchecked)
`?attr/colorSecondary` (checked)
+**Checkable** | `android:checkable` | `setCheckable`
`isCheckable` | `false`
+**Size** | `checkedIconSize` | `setCheckedIconSize`
`setCheckedIconSizeResource`
`getCheckedIconSize` | `24dp`
+**Margin** | `checkedIconMargin` | `setCheckedIconMargin`
`setCheckedIconMarginResource`
`getCheckedIconMargin` | `8dp`
+**Gravity** | `checkedIconGravity` | `setCheckedIconGravity`
`getCheckedIconGravity` | `TOP_END`
#### States
diff --git a/lib/java/com/google/android/material/card/MaterialCardView.java b/lib/java/com/google/android/material/card/MaterialCardView.java
index ada421427ac..7dea7183f4c 100644
--- a/lib/java/com/google/android/material/card/MaterialCardView.java
+++ b/lib/java/com/google/android/material/card/MaterialCardView.java
@@ -40,6 +40,7 @@
import androidx.annotation.Dimension;
import androidx.annotation.DrawableRes;
import androidx.annotation.FloatRange;
+import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.cardview.widget.CardView;
@@ -48,6 +49,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.
@@ -94,6 +97,48 @@ 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
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CheckedIconGravity{}
+
@NonNull private final MaterialCardViewHelper cardViewHelper;
/**
@@ -635,4 +680,29 @@ 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);
+ }
+ }
}
diff --git a/lib/java/com/google/android/material/card/MaterialCardViewHelper.java b/lib/java/com/google/android/material/card/MaterialCardViewHelper.java
index d141ad6a093..cfdee2f9313 100644
--- a/lib/java/com/google/android/material/card/MaterialCardViewHelper.java
+++ b/lib/java/com/google/android/material/card/MaterialCardViewHelper.java
@@ -19,6 +19,9 @@
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 android.content.res.ColorStateList;
import android.content.res.TypedArray;
@@ -45,6 +48,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;
@@ -96,6 +100,7 @@ class MaterialCardViewHelper {
@Dimension private int checkedIconMargin;
@Dimension private int checkedIconSize;
+ @CheckedIconGravity private int checkedIconGravity;
@Dimension private int strokeWidth;
// If card is clickable, this is the clickableForegroundDrawable otherwise it draws the stroke.
@@ -161,6 +166,9 @@ void loadFromAttributes(@NonNull TypedArray attributes) {
attributes.getDimensionPixelSize(R.styleable.MaterialCardView_checkedIconSize, 0));
setCheckedIconMargin(
attributes.getDimensionPixelSize(R.styleable.MaterialCardView_checkedIconMargin, 0));
+ checkedIconGravity =
+ attributes.getInteger(
+ R.styleable.MaterialCardView_checkedIconGravity, CHECKED_ICON_GRAVITY_TOP_END);
rippleColor =
MaterialResources.getColorStateList(
@@ -413,15 +421,30 @@ void setCheckedIconMargin(@Dimension int checkedIconMargin) {
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;
@@ -430,7 +453,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);
}
}
@@ -656,4 +679,23 @@ public void setChecked(boolean checked) {
checkedIcon.setAlpha(checked ? 255 : 0);
}
}
+
+ @CheckedIconGravity
+ int getCheckedIconGravity() {
+ return checkedIconGravity;
+ }
+
+ void setCheckedIconGravity(@CheckedIconGravity int checkedIconGravity) {
+ this.checkedIconGravity = checkedIconGravity;
+ }
+
+ private boolean isCheckedIconEnd() {
+ return checkedIconGravity == CHECKED_ICON_GRAVITY_TOP_END
+ || checkedIconGravity == CHECKED_ICON_GRAVITY_BOTTOM_END;
+ }
+
+ private boolean isCheckedIconBottom() {
+ return checkedIconGravity == CHECKED_ICON_GRAVITY_BOTTOM_START
+ || checkedIconGravity == CHECKED_ICON_GRAVITY_BOTTOM_END;
+ }
}
diff --git a/lib/java/com/google/android/material/card/res-public/values/public.xml b/lib/java/com/google/android/material/card/res-public/values/public.xml
index e3ee6679798..b40f8a9545b 100644
--- a/lib/java/com/google/android/material/card/res-public/values/public.xml
+++ b/lib/java/com/google/android/material/card/res-public/values/public.xml
@@ -18,6 +18,7 @@
+
diff --git a/lib/java/com/google/android/material/card/res/values/attrs.xml b/lib/java/com/google/android/material/card/res/values/attrs.xml
index 51c9aba4ce5..cb120cdf380 100644
--- a/lib/java/com/google/android/material/card/res/values/attrs.xml
+++ b/lib/java/com/google/android/material/card/res/values/attrs.xml
@@ -45,6 +45,17 @@
+
+
+
+
+
+
+
+
+
+
+