Skip to content

Commit

Permalink
[Button] Support icon gravity with text alignments other than centered
Browse files Browse the repository at this point in the history
Resolves #1371

PiperOrigin-RevId: 421605261
  • Loading branch information
drchen authored and dsn5ft committed Jan 18, 2022
1 parent e98cee5 commit 6c41f07
Showing 1 changed file with 71 additions and 8 deletions.
79 changes: 71 additions & 8 deletions lib/java/com/google/android/material/button/MaterialButton.java
Expand Up @@ -35,8 +35,10 @@
import android.os.Parcelable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.AppCompatButton;
import android.text.Layout.Alignment;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Button;
Expand Down Expand Up @@ -493,28 +495,89 @@ public void refreshDrawableState() {
}
}

@RequiresApi(VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void setTextAlignment(int textAlignment) {
super.setTextAlignment(textAlignment);
updateIconPosition(getMeasuredWidth(), getMeasuredHeight());
}

/**
* This method and {@link #getActualTextAlignment()} is modified from Android framework TextView's
* private method getLayoutAlignment(). Please note that the logic here assumes the actual text
* direction is the same as the layout direction, which is not always the case, especially when
* the text mixes different languages. However, this is probably the best we can do for now,
* unless we have a good way to detect the final text direction being used by TextView.
*/
private Alignment getGravityTextAlignment() {
switch (getGravity() & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
return Alignment.ALIGN_CENTER;
case Gravity.END:
case Gravity.RIGHT:
return Alignment.ALIGN_OPPOSITE;
case Gravity.START:
case Gravity.LEFT:
default:
return Alignment.ALIGN_NORMAL;
}
}

/**
* This method and {@link #getGravityTextAlignment()} is modified from Android framework
* TextView's private method getLayoutAlignment(). Please note that the logic here assumes
* the actual text direction is the same as the layout direction, which is not always the case,
* especially when the text mixes different languages. However, this is probably the best we can
* do for now, unless we have a good way to detect the final text direction being used by
* TextView.
*/
private Alignment getActualTextAlignment() {
if (VERSION.SDK_INT < VERSION_CODES.JELLY_BEAN_MR1) {
return getGravityTextAlignment();
}
switch (getTextAlignment()) {
case TEXT_ALIGNMENT_GRAVITY:
return getGravityTextAlignment();
case TEXT_ALIGNMENT_CENTER:
return Alignment.ALIGN_CENTER;
case TEXT_ALIGNMENT_TEXT_END:
case TEXT_ALIGNMENT_VIEW_END:
return Alignment.ALIGN_OPPOSITE;
case TEXT_ALIGNMENT_TEXT_START:
case TEXT_ALIGNMENT_VIEW_START:
case TEXT_ALIGNMENT_INHERIT:
default:
return Alignment.ALIGN_NORMAL;
}
}

private void updateIconPosition(int buttonWidth, int buttonHeight) {
if (icon == null || getLayout() == null) {
return;
}

if (isIconStart() || isIconEnd()) {
iconTop = 0;
if (iconGravity == ICON_GRAVITY_START || iconGravity == ICON_GRAVITY_END) {

Alignment textAlignment = getActualTextAlignment();
if (iconGravity == ICON_GRAVITY_START
|| iconGravity == ICON_GRAVITY_END
|| (iconGravity == ICON_GRAVITY_TEXT_START && textAlignment == Alignment.ALIGN_NORMAL)
|| (iconGravity == ICON_GRAVITY_TEXT_END && textAlignment == Alignment.ALIGN_OPPOSITE)) {
iconLeft = 0;
updateIcon(/* needsIconReset = */ false);
return;
}

int localIconSize = iconSize == 0 ? icon.getIntrinsicWidth() : iconSize;
int availableWidth = buttonWidth
- getTextWidth()
- ViewCompat.getPaddingEnd(this)
- localIconSize
- iconPadding
- ViewCompat.getPaddingStart(this);
int newIconLeft =
(buttonWidth
- getTextWidth()
- ViewCompat.getPaddingEnd(this)
- localIconSize
- iconPadding
- ViewCompat.getPaddingStart(this))
/ 2;
textAlignment == Alignment.ALIGN_CENTER ? availableWidth / 2 : availableWidth;

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

0 comments on commit 6c41f07

Please sign in to comment.