Why does TextView have end padding when multi line?

前端 未结 4 779
执念已碎
执念已碎 2021-02-07 06:27

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

相关标签:
4条回答
  • 2021-02-07 07:06

    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);
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-07 07:07

    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;
      }
    }
    
    0 讨论(0)
  • 2021-02-07 07:12

    I recently faced a similar problem when developing a chat-bubble view for an app, so I used the ideas from the accepted solution, and @hoffware's improvements, and re-implemented them in Kotlin.

    import android.content.Context
    import android.util.AttributeSet
    import android.view.View.MeasureSpec.*
    import androidx.appcompat.widget.AppCompatTextView
    import kotlin.math.ceil
    
    class TightTextView
    @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = android.R.attr.textViewStyle
    ) : AppCompatTextView(context, attrs, defStyleAttr) {
    
        override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    
            val lineCount = layout.lineCount
            if (lineCount > 1 && getMode(widthMeasureSpec) != EXACTLY) {
                val textWidth = (0 until lineCount).maxOf(layout::getLineWidth)
                val padding = compoundPaddingLeft + compoundPaddingRight
                val w = ceil(textWidth).toInt() + padding
    
                if (w < measuredWidth) {
                    val newWidthMeasureSpec = makeMeasureSpec(w, AT_MOST)
                    super.onMeasure(newWidthMeasureSpec, heightMeasureSpec)
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-07 07:18

    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.

    0 讨论(0)
提交回复
热议问题