Why does TextView have end padding when multi line?

半城伤御伤魂 提交于 2020-02-26 09:12:09

问题


If you have a TextView with layout_width="wrap_content" and it has to wrap to a second line to contain the text, then it will size its width to use up all of the space available (respecting margins etc). But why is there padding at the end of the view? I just told it to wrap_content, so it should wrap that content! This seems like a bug, this is visible in the chat UI of the stock Messenger app. (The image is from my own app though. But that extra space is definitely not in the 9 patch.)

Any workaround?

Update: Responders/commenters missed the point. Maybe the image I uploaded was misleading because it was styled from my app. The problem occurs with any TextView, you can see by styling the background that the view bounds will no longer be tight. I uploaded a different image. Here is the XML for the TextViews in the image:

        <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginEnd="20dp"
    android:layout_marginStart="20dp"
    android:background="#dddddd"
    android:text="This doesn't wrap"
    android:layout_marginTop="20dp"
    android:layout_marginBottom="20dp"
    android:layout_gravity="center_horizontal"
    />
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginEnd="20dp"
    android:layout_marginStart="20dp"
    android:layout_gravity="center_horizontal"
    android:background="#dddddd"
    android:text="This wraps and look, the bounds does not fit tight against the right edge of text"
    />


回答1:


At first, when seeing your post, i thought that the problem was because standard Android TextView have some default padding defined in their base style. If one wants to remove it, ones can try it something like :

android:paddingEnd="0dp"

or

android:paddingRight="0dp"

As your post has been updated, I understand that your problem does not comes from padding, but from word wrapping. Indeed, when there are several lines to display, Android TextView use the whole available space in width.

As stated in this post, there is no standard solution for this and you will need to customize your text view to fix its width after filling it.

Overriding onMeasure method of your textView like below shoud work (inspired from "sky" answer) :

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int specModeW = MeasureSpec.getMode(widthMeasureSpec);
    if (specModeW != MeasureSpec.EXACTLY) {
        Layout layout = getLayout();
        int linesCount = layout.getLineCount();
        if (linesCount > 1) {
            float textRealMaxWidth = 0;
            for (int n = 0; n < linesCount; ++n) {
                textRealMaxWidth = Math.max(textRealMaxWidth, layout.getLineWidth(n));
            }
            int w = (int) Math.ceil(textRealMaxWidth);
            if (w < getMeasuredWidth()) {
                super.onMeasure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.AT_MOST),
                        heightMeasureSpec);
            }
        }
    }
}



回答2:


I found the selected answer to be helpful, although it didn't quite account for padding. I combined the selected answer with this post's answer to come up with a view that works with padding. FYI, the other post's answer had a flaw where the view would sometimes get cut-off at the end by a few pixels.

public class TightTextView extends TextView {
  public TightTextView(Context context) {
    super(context);
  }

  public TightTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public TightTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int specModeW = MeasureSpec.getMode(widthMeasureSpec);
    if (specModeW != MeasureSpec.EXACTLY) {
      Layout layout = getLayout();
      if (layout != null) {
        int w = (int) Math.ceil(getMaxLineWidth(layout)) + getCompoundPaddingLeft() + getCompoundPaddingRight();
        if (w < getMeasuredWidth()) {
          super.onMeasure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.AT_MOST),
          heightMeasureSpec);
        }
      }
    }
  }

  private float getMaxLineWidth(Layout layout) {
    float max_width = 0.0f;
    int lines = layout.getLineCount();
    for (int i = 0; i < lines; i++) {
      if (layout.getLineWidth(i) > max_width) {
        max_width = layout.getLineWidth(i);
      }
    }
    return max_width;
  }
}



回答3:


Pretty sure this is because "against" doesn't fit between the word "fit" and the right edge. If you want to test this out, try changing your text to a bunch of |'s with a single space between each one.



来源:https://stackoverflow.com/questions/40800808/why-does-textview-have-end-padding-when-multi-line

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!