Skip to content

Commit 250d56d

Browse files
gabrielemariottidrchen
authored andcommitted
[MaterialCardView] Added option to set the checkedIcon gravity
Resolves #1679 GIT_ORIGIN_REV_ID=a35c862071d83ced72c4d7257f2b7bc93101bfbb PiperOrigin-RevId: 407662373
1 parent a369449 commit 250d56d

File tree

5 files changed

+136
-11
lines changed

5 files changed

+136
-11
lines changed

docs/components/Card.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -380,13 +380,14 @@ border, regardless of the `app:strokeWidth` value.
380380

381381
#### Checked icon attributes
382382

383-
Element | Attribute | Related method(s) | Default value
384-
------------- | ------------------- | ------------------------------------------------------------------------------------ | -------------
385-
**Icon** | `checkedIcon` | `setCheckedIcon`<br/>`setCheckedIconResource`<br/>`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)
386-
**Color** | `checkedIconTint` | `setCheckedIconTint`<br/>`getCheckedIconTint` | `?attr/colorOutline` (unchecked)<br/>`?attr/colorSecondary` (checked)
387-
**Checkable** | `android:checkable` | `setCheckable`<br/>`isCheckable` | `false`
388-
**Size** | `checkedIconSize` | `setCheckedIconSize`<br/>`setCheckedIconSizeResource`<br/>`getCheckedIconSize` | `24dp`
389-
**Margin** | `checkedIconMargin` | `setCheckedIconMargin`<br/>`setCheckedIconMarginResource`<br/>`getCheckedIconMargin` | `8dp`
383+
Element | Attribute | Related method(s) | Default value
384+
------------- | -------------------- | ------------------------------------------------------------------------------------ | -------------
385+
**Icon** | `checkedIcon` | `setCheckedIcon`<br/>`setCheckedIconResource`<br/>`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)
386+
**Color** | `checkedIconTint` | `setCheckedIconTint`<br/>`getCheckedIconTint` | `?attr/colorOutline` (unchecked)<br/>`?attr/colorSecondary` (checked)
387+
**Checkable** | `android:checkable` | `setCheckable`<br/>`isCheckable` | `false`
388+
**Size** | `checkedIconSize` | `setCheckedIconSize`<br/>`setCheckedIconSizeResource`<br/>`getCheckedIconSize` | `24dp`
389+
**Margin** | `checkedIconMargin` | `setCheckedIconMargin`<br/>`setCheckedIconMarginResource`<br/>`getCheckedIconMargin` | `8dp`
390+
**Gravity** | `checkedIconGravity` | `setCheckedIconGravity`<br/>`getCheckedIconGravity` | `TOP_END`
390391

391392
#### States
392393

lib/java/com/google/android/material/card/MaterialCardView.java

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import androidx.annotation.Dimension;
4141
import androidx.annotation.DrawableRes;
4242
import androidx.annotation.FloatRange;
43+
import androidx.annotation.IntDef;
4344
import androidx.annotation.NonNull;
4445
import androidx.annotation.Nullable;
4546
import androidx.cardview.widget.CardView;
@@ -48,6 +49,8 @@
4849
import com.google.android.material.shape.MaterialShapeUtils;
4950
import com.google.android.material.shape.ShapeAppearanceModel;
5051
import com.google.android.material.shape.Shapeable;
52+
import java.lang.annotation.Retention;
53+
import java.lang.annotation.RetentionPolicy;
5154

5255
/**
5356
* Provides a Material card.
@@ -94,6 +97,48 @@ public interface OnCheckedChangeListener {
9497
private static final String LOG_TAG = "MaterialCardView";
9598
private static final String ACCESSIBILITY_CLASS_NAME = "androidx.cardview.widget.CardView";
9699

100+
/**
101+
* Gravity used to position the checked icon at the top|start of the Card.
102+
*
103+
* @see #setCheckedIconGravity(int)
104+
* @see #getCheckedIconGravity()
105+
*/
106+
public static final int CHECKED_ICON_GRAVITY_TOP_START = 0x1;
107+
108+
/**
109+
* Gravity used to position the checked icon at the bottom|start of the Card.
110+
*
111+
* @see #setCheckedIconGravity(int)
112+
* @see #getCheckedIconGravity()
113+
*/
114+
public static final int CHECKED_ICON_GRAVITY_BOTTOM_START = 0x2;
115+
116+
/**
117+
* Gravity used to position the checked icon at the top|end of the Card.
118+
*
119+
* @see #setCheckedIconGravity(int)
120+
* @see #getCheckedIconGravity()
121+
*/
122+
public static final int CHECKED_ICON_GRAVITY_TOP_END = 0x3;
123+
124+
/**
125+
* Gravity used to position the checked icon at the bottom|end of the Card.
126+
*
127+
* @see #setCheckedIconGravity(int)
128+
* @see #getCheckedIconGravity()
129+
*/
130+
public static final int CHECKED_ICON_GRAVITY_BOTTOM_END = 0x4;
131+
132+
/** Positions the icon can be set to. */
133+
@IntDef({
134+
CHECKED_ICON_GRAVITY_TOP_START,
135+
CHECKED_ICON_GRAVITY_BOTTOM_START,
136+
CHECKED_ICON_GRAVITY_TOP_END,
137+
CHECKED_ICON_GRAVITY_BOTTOM_END
138+
})
139+
@Retention(RetentionPolicy.SOURCE)
140+
public @interface CheckedIconGravity{}
141+
97142
@NonNull private final MaterialCardViewHelper cardViewHelper;
98143

99144
/**
@@ -635,4 +680,29 @@ private void forceRippleRedrawIfNeeded() {
635680
cardViewHelper.forceRippleRedraw();
636681
}
637682
}
683+
684+
/**
685+
* Gets the checked icon gravity for this card
686+
*
687+
* @return Checked Icon gravity of the card.
688+
* @attr ref com.google.android.material.R.styleable#MaterialCard_checkedIconGravity
689+
* @see #setCheckedIconGravity(int)
690+
*/
691+
@CheckedIconGravity
692+
public int getCheckedIconGravity() {
693+
return cardViewHelper.getCheckedIconGravity();
694+
}
695+
696+
/**
697+
* Sets the checked icon gravity for this card
698+
*
699+
* @attr ref com.google.android.material.R.styleable#MaterialCard_checkedIconGravity
700+
* @param checkedIconGravity checked icon gravity for this card
701+
* @see #getCheckedIconGravity()
702+
*/
703+
public void setCheckedIconGravity(@CheckedIconGravity int checkedIconGravity) {
704+
if (cardViewHelper.getCheckedIconGravity() != checkedIconGravity) {
705+
cardViewHelper.setCheckedIconGravity(checkedIconGravity);
706+
}
707+
}
638708
}

lib/java/com/google/android/material/card/MaterialCardViewHelper.java

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
import com.google.android.material.R;
2020

2121
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
22+
import static com.google.android.material.card.MaterialCardView.CHECKED_ICON_GRAVITY_BOTTOM_END;
23+
import static com.google.android.material.card.MaterialCardView.CHECKED_ICON_GRAVITY_BOTTOM_START;
24+
import static com.google.android.material.card.MaterialCardView.CHECKED_ICON_GRAVITY_TOP_END;
2225

2326
import android.content.res.ColorStateList;
2427
import android.content.res.TypedArray;
@@ -45,6 +48,7 @@
4548
import androidx.annotation.RestrictTo;
4649
import androidx.annotation.StyleRes;
4750
import androidx.cardview.widget.CardView;
51+
import com.google.android.material.card.MaterialCardView.CheckedIconGravity;
4852
import com.google.android.material.color.MaterialColors;
4953
import com.google.android.material.resources.MaterialResources;
5054
import com.google.android.material.ripple.RippleUtils;
@@ -96,6 +100,7 @@ class MaterialCardViewHelper {
96100

97101
@Dimension private int checkedIconMargin;
98102
@Dimension private int checkedIconSize;
103+
@CheckedIconGravity private int checkedIconGravity;
99104
@Dimension private int strokeWidth;
100105

101106
// If card is clickable, this is the clickableForegroundDrawable otherwise it draws the stroke.
@@ -161,6 +166,9 @@ void loadFromAttributes(@NonNull TypedArray attributes) {
161166
attributes.getDimensionPixelSize(R.styleable.MaterialCardView_checkedIconSize, 0));
162167
setCheckedIconMargin(
163168
attributes.getDimensionPixelSize(R.styleable.MaterialCardView_checkedIconMargin, 0));
169+
checkedIconGravity =
170+
attributes.getInteger(
171+
R.styleable.MaterialCardView_checkedIconGravity, CHECKED_ICON_GRAVITY_TOP_END);
164172

165173
rippleColor =
166174
MaterialResources.getColorStateList(
@@ -413,15 +421,30 @@ void setCheckedIconMargin(@Dimension int checkedIconMargin) {
413421

414422
void onMeasure(int measuredWidth, int measuredHeight) {
415423
if (clickableForegroundDrawable != null) {
416-
int left = measuredWidth - checkedIconMargin - checkedIconSize;
417-
int bottom = measuredHeight - checkedIconMargin - checkedIconSize;
424+
int left =
425+
isCheckedIconEnd()
426+
? measuredWidth - checkedIconMargin - checkedIconSize
427+
: checkedIconMargin;
428+
int bottom =
429+
isCheckedIconBottom()
430+
? checkedIconMargin
431+
: measuredHeight - checkedIconMargin - checkedIconSize;
432+
418433
boolean isPreLollipop = VERSION.SDK_INT < VERSION_CODES.LOLLIPOP;
419434
if (isPreLollipop || materialCardView.getUseCompatPadding()) {
420435
bottom -= (int) Math.ceil(2f * calculateVerticalBackgroundPadding());
421436
left -= (int) Math.ceil(2f * calculateHorizontalBackgroundPadding());
422437
}
423438

424-
int right = checkedIconMargin;
439+
int right =
440+
isCheckedIconEnd()
441+
? checkedIconMargin
442+
: measuredWidth - checkedIconMargin - checkedIconSize;
443+
int top =
444+
isCheckedIconBottom()
445+
? measuredHeight - checkedIconMargin - checkedIconSize
446+
: checkedIconMargin;
447+
425448
if (ViewCompat.getLayoutDirection(materialCardView) == ViewCompat.LAYOUT_DIRECTION_RTL) {
426449
// swap left and right
427450
int tmp = right;
@@ -430,7 +453,7 @@ void onMeasure(int measuredWidth, int measuredHeight) {
430453
}
431454

432455
clickableForegroundDrawable.setLayerInset(
433-
CHECKED_ICON_LAYER_INDEX, left, checkedIconMargin /* top */, right, bottom);
456+
CHECKED_ICON_LAYER_INDEX, left, top /* top */, right, bottom);
434457
}
435458
}
436459

@@ -656,4 +679,23 @@ public void setChecked(boolean checked) {
656679
checkedIcon.setAlpha(checked ? 255 : 0);
657680
}
658681
}
682+
683+
@CheckedIconGravity
684+
int getCheckedIconGravity() {
685+
return checkedIconGravity;
686+
}
687+
688+
void setCheckedIconGravity(@CheckedIconGravity int checkedIconGravity) {
689+
this.checkedIconGravity = checkedIconGravity;
690+
}
691+
692+
private boolean isCheckedIconEnd() {
693+
return checkedIconGravity == CHECKED_ICON_GRAVITY_TOP_END
694+
|| checkedIconGravity == CHECKED_ICON_GRAVITY_BOTTOM_END;
695+
}
696+
697+
private boolean isCheckedIconBottom() {
698+
return checkedIconGravity == CHECKED_ICON_GRAVITY_BOTTOM_START
699+
|| checkedIconGravity == CHECKED_ICON_GRAVITY_BOTTOM_END;
700+
}
659701
}

lib/java/com/google/android/material/card/res-public/values/public.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<public name="cardForegroundColor" type="attr"/>
1919
<public name="checkedIconSize" type="attr"/>
2020
<public name="checkedIconMargin" type="attr"/>
21+
<public name="checkedIconGravity" type="attr"/>
2122
<public name="materialCardViewStyle" type="attr"/>
2223
<public name="materialCardViewOutlinedStyle" type="attr"/>
2324
<public name="materialCardViewFilledStyle" type="attr"/>

lib/java/com/google/android/material/card/res/values/attrs.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@
4545
<attr name="checkedIconSize" format="dimension"/>
4646
<!-- Check icon margin for Checkable Cards-->
4747
<attr name="checkedIconMargin" format="dimension"/>
48+
<!-- Specifies how the checked icon should be positioned. -->
49+
<attr name="checkedIconGravity">
50+
<!-- Push icon to the top|start of the card. -->
51+
<flag name="TOP_START" value="0x1"/>
52+
<!-- Push icon to the bottom|start of the card. -->
53+
<flag name="BOTTOM_START" value="0x2"/>
54+
<!-- Push icon to the top|end of the card. -->
55+
<flag name="TOP_END" value="0x3"/>
56+
<!-- Push icon to the bottom|end of the card. -->
57+
<flag name="BOTTOM_END" value="0x4"/>
58+
</attr>
4859
<!-- Ripple color for the Card. -->
4960
<attr name="rippleColor"/>
5061
<!-- State when a Card is being dragged. -->

0 commit comments

Comments
 (0)