Skip to content

Commit 6c41f07

Browse files
drchendsn5ft
authored andcommitted
[Button] Support icon gravity with text alignments other than centered
Resolves #1371 PiperOrigin-RevId: 421605261
1 parent e98cee5 commit 6c41f07

File tree

1 file changed

+71
-8
lines changed

1 file changed

+71
-8
lines changed

lib/java/com/google/android/material/button/MaterialButton.java

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@
3535
import android.os.Parcelable;
3636
import androidx.appcompat.content.res.AppCompatResources;
3737
import androidx.appcompat.widget.AppCompatButton;
38+
import android.text.Layout.Alignment;
3839
import android.util.AttributeSet;
3940
import android.util.Log;
41+
import android.view.Gravity;
4042
import android.view.accessibility.AccessibilityEvent;
4143
import android.view.accessibility.AccessibilityNodeInfo;
4244
import android.widget.Button;
@@ -493,28 +495,89 @@ public void refreshDrawableState() {
493495
}
494496
}
495497

498+
@RequiresApi(VERSION_CODES.JELLY_BEAN_MR1)
499+
@Override
500+
public void setTextAlignment(int textAlignment) {
501+
super.setTextAlignment(textAlignment);
502+
updateIconPosition(getMeasuredWidth(), getMeasuredHeight());
503+
}
504+
505+
/**
506+
* This method and {@link #getActualTextAlignment()} is modified from Android framework TextView's
507+
* private method getLayoutAlignment(). Please note that the logic here assumes the actual text
508+
* direction is the same as the layout direction, which is not always the case, especially when
509+
* the text mixes different languages. However, this is probably the best we can do for now,
510+
* unless we have a good way to detect the final text direction being used by TextView.
511+
*/
512+
private Alignment getGravityTextAlignment() {
513+
switch (getGravity() & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) {
514+
case Gravity.CENTER_HORIZONTAL:
515+
return Alignment.ALIGN_CENTER;
516+
case Gravity.END:
517+
case Gravity.RIGHT:
518+
return Alignment.ALIGN_OPPOSITE;
519+
case Gravity.START:
520+
case Gravity.LEFT:
521+
default:
522+
return Alignment.ALIGN_NORMAL;
523+
}
524+
}
525+
526+
/**
527+
* This method and {@link #getGravityTextAlignment()} is modified from Android framework
528+
* TextView's private method getLayoutAlignment(). Please note that the logic here assumes
529+
* the actual text direction is the same as the layout direction, which is not always the case,
530+
* especially when the text mixes different languages. However, this is probably the best we can
531+
* do for now, unless we have a good way to detect the final text direction being used by
532+
* TextView.
533+
*/
534+
private Alignment getActualTextAlignment() {
535+
if (VERSION.SDK_INT < VERSION_CODES.JELLY_BEAN_MR1) {
536+
return getGravityTextAlignment();
537+
}
538+
switch (getTextAlignment()) {
539+
case TEXT_ALIGNMENT_GRAVITY:
540+
return getGravityTextAlignment();
541+
case TEXT_ALIGNMENT_CENTER:
542+
return Alignment.ALIGN_CENTER;
543+
case TEXT_ALIGNMENT_TEXT_END:
544+
case TEXT_ALIGNMENT_VIEW_END:
545+
return Alignment.ALIGN_OPPOSITE;
546+
case TEXT_ALIGNMENT_TEXT_START:
547+
case TEXT_ALIGNMENT_VIEW_START:
548+
case TEXT_ALIGNMENT_INHERIT:
549+
default:
550+
return Alignment.ALIGN_NORMAL;
551+
}
552+
}
553+
496554
private void updateIconPosition(int buttonWidth, int buttonHeight) {
497555
if (icon == null || getLayout() == null) {
498556
return;
499557
}
500558

501559
if (isIconStart() || isIconEnd()) {
502560
iconTop = 0;
503-
if (iconGravity == ICON_GRAVITY_START || iconGravity == ICON_GRAVITY_END) {
561+
562+
Alignment textAlignment = getActualTextAlignment();
563+
if (iconGravity == ICON_GRAVITY_START
564+
|| iconGravity == ICON_GRAVITY_END
565+
|| (iconGravity == ICON_GRAVITY_TEXT_START && textAlignment == Alignment.ALIGN_NORMAL)
566+
|| (iconGravity == ICON_GRAVITY_TEXT_END && textAlignment == Alignment.ALIGN_OPPOSITE)) {
504567
iconLeft = 0;
505568
updateIcon(/* needsIconReset = */ false);
506569
return;
507570
}
508571

509572
int localIconSize = iconSize == 0 ? icon.getIntrinsicWidth() : iconSize;
573+
int availableWidth = buttonWidth
574+
- getTextWidth()
575+
- ViewCompat.getPaddingEnd(this)
576+
- localIconSize
577+
- iconPadding
578+
- ViewCompat.getPaddingStart(this);
510579
int newIconLeft =
511-
(buttonWidth
512-
- getTextWidth()
513-
- ViewCompat.getPaddingEnd(this)
514-
- localIconSize
515-
- iconPadding
516-
- ViewCompat.getPaddingStart(this))
517-
/ 2;
580+
textAlignment == Alignment.ALIGN_CENTER ? availableWidth / 2 : availableWidth;
518581

519582
// Only flip the bound value if either isLayoutRTL() or iconGravity is textEnd, but not both
520583
if (isLayoutRTL() != (iconGravity == ICON_GRAVITY_TEXT_END)) {

0 commit comments

Comments
 (0)