|
35 | 35 | import android.os.Parcelable; |
36 | 36 | import androidx.appcompat.content.res.AppCompatResources; |
37 | 37 | import androidx.appcompat.widget.AppCompatButton; |
| 38 | +import android.text.Layout.Alignment; |
38 | 39 | import android.util.AttributeSet; |
39 | 40 | import android.util.Log; |
| 41 | +import android.view.Gravity; |
40 | 42 | import android.view.accessibility.AccessibilityEvent; |
41 | 43 | import android.view.accessibility.AccessibilityNodeInfo; |
42 | 44 | import android.widget.Button; |
@@ -493,28 +495,89 @@ public void refreshDrawableState() { |
493 | 495 | } |
494 | 496 | } |
495 | 497 |
|
| 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 | + |
496 | 554 | private void updateIconPosition(int buttonWidth, int buttonHeight) { |
497 | 555 | if (icon == null || getLayout() == null) { |
498 | 556 | return; |
499 | 557 | } |
500 | 558 |
|
501 | 559 | if (isIconStart() || isIconEnd()) { |
502 | 560 | 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)) { |
504 | 567 | iconLeft = 0; |
505 | 568 | updateIcon(/* needsIconReset = */ false); |
506 | 569 | return; |
507 | 570 | } |
508 | 571 |
|
509 | 572 | 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); |
510 | 579 | 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; |
518 | 581 |
|
519 | 582 | // Only flip the bound value if either isLayoutRTL() or iconGravity is textEnd, but not both |
520 | 583 | if (isLayoutRTL() != (iconGravity == ICON_GRAVITY_TEXT_END)) { |
|
0 commit comments