如何在Android的TextView上去除顶部和底部的空白

66

当我把下面的 XML 包含到 layout 文件中时,我可以看到下面的图片。如果你看到了它,你会发现 TextView 有顶部和底部的空间。

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="E1"
android:background="#ff00ff00"/>

enter image description here

我想要去掉这个空格。如何去掉它?这个叫什么? 如果有人知道,请告诉我。谢谢。


可能是重复的问题:Android:TextView:删除顶部和底部的间距和填充 - Mohammed Atif
14个回答

99
尝试使用 android:includeFontPadding="false" 看看是否有帮助。根据我的经验,这样做会稍微有所改善,但无法将 TextView 的尺寸缩减到完全符合像素精确的文本大小。
唯一的替代方案是有些欺骗性的方式,即将尺寸硬编码以匹配文本大小,例如将高度设置为"24sp" 而不是 "wrap_content",这可能会产生更好的结果,但具体情况因人而异。

4
赞同第二个观点!只需注意我还必须包含 includeFontPadding="false",否则文字会被裁剪一点。 - Enrichman
2
这对我来说是一项工作。但如何去除文本上升和下降之上和之下的顶部和底部空间? - Harshil Dholakiya
第二个剪辑了我的内容。 - Dot Cink

33

我曾经遇到过同样的问题。属性 android:includeFontPadding="false" 对我无效。我通过以下方式解决了这个问题:

public class TextViewWithoutPaddings extends TextView {

    private final Paint mPaint = new Paint();

    private final Rect mBounds = new Rect();

    public TextViewWithoutPaddings(Context context) {
        super(context);
    }

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

    public TextViewWithoutPaddings(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(@NonNull Canvas canvas) {
        final String text = calculateTextParams();

        final int left = mBounds.left;
        final int bottom = mBounds.bottom;
        mBounds.offset(-mBounds.left, -mBounds.top);
        mPaint.setAntiAlias(true);
        mPaint.setColor(getCurrentTextColor());
        canvas.drawText(text, -left, mBounds.bottom - bottom, mPaint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        calculateTextParams();
        setMeasuredDimension(mBounds.width() + 1, -mBounds.top + 1);
    }

    private String calculateTextParams() {
        final String text = getText().toString();
        final int textLength = text.length();
        mPaint.setTextSize(getTextSize());
        mPaint.getTextBounds(text, 0, textLength, mBounds);
        if (textLength == 0) {
            mBounds.right = mBounds.left;
        }
        return text;
    }
}

2
很棒的解决方案!尝试了不同的文本大小,效果非常好 :) - dakshbhatt21
2
更新:在上面的代码中,当我使用小写字母 q、g、y、p 时,它们从底部被切掉了。因此,需要将 setMeasuredDimension(mBounds.width() + 1, -mBounds.top + 1); 更改为 setMeasuredDimension(mBounds.width() + 1, -mBounds.top + mBounds.bottom); - dakshbhatt21
从性能角度来看,在onDraw()中调用calculateTextParams似乎不是一个好主意。 - sandrstar
4
如果您指定了android:fontFamily,那么请将mPaint更改为getPaint(),否则字体族不会应用。 - YetAnotherUser
对我没用。它修剪了填充,但字体居中了,因此大部分字体也被裁剪了。我使用的是大字体(56sp),如果有区别的话。 - Jeffrey Blattman
它可以使用一行代码工作,但是当我使用“\n”添加多行时,它只显示在一行中。 - VIISHRUT MAVANII

24

android:includeFontPadding="false" 虽然很好用,但有时候并不能完全达到效果。如果你需要精确控制边框位置,可以通过应用负边距来自己解决:

尝试将底部和顶部边距设置为负值。

类似于这样:

android:layout_marginTop="-5dp"
android:layout_marginBottom="-5dp"

根据需要适当调整数值。


这正好做到了我需要它做的事情。这应该是被接受的答案。适用于运行> API 21的设备。 - InnisBrendan
1
我仍在努力理解答案的赞数:)) - Farid
这个运行良好,但它是可扩展的解决方案吗? - Parth Anjaria
如果我没记错的话,在最新的约束布局中,负边距现在可以使用。如果我错了,请有人告诉我。 - j2emanue

5

这是拯救我们一天的代码。它是使用来自maksimko的mono C#代码进行调整的:

public class TopAlignedTextView extends TextView {

    public TopAlignedTextView(Context context) {
        super(context);
    }

    /*This is where the magic happens*/
    @Override
    protected void onDraw(Canvas canvas){

        float offset = getTextSize() - getLineHeight();
        canvas.translate(0, offset);
        super.onDraw(canvas);
    }
}

因为我们要对齐不同字体大小的 TextViews,所以仍需使用 textView.setIncludeFontPadding(false) 进行调整。


3
可以考虑展示堆栈跟踪信息,而不是对一个对许多用户有用的答案进行贬低评价吗? - Henrique de Sousa

4
我遇到了同样的问题。 这里有一个好的解答:如何将文本对齐到TextView顶部? 但是代码有点不完整,不支持所有字体大小。请修改以下代码行:
int additionalPadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getContext().getResources().getDisplayMetrics());

to

int additionalPadding = getTextSize() - getLineHeight();

完整的C#代码(mono)移除顶部偏移:

public class TextControl : TextView {
    public TextControl (Context context) : base (context)
    {
        SetIncludeFontPadding (false);
        Gravity = GravityFlags.Top;
    }

    protected override void OnDraw (Android.Graphics.Canvas canvas)
    {
        if (base.Layout == null)
            return;

        Paint.Color = new Android.Graphics.Color (CurrentTextColor);
        Paint.DrawableState = GetDrawableState ();

        canvas.Save ();

        var offset = TextSize - LineHeight;
        canvas.Translate (0, offset);

        base.Layout.Draw (canvas);

        canvas.Restore ();
    }
}

参考示例在最后一刻反转了翻译金额,而这段代码没有。除此之外,解决方案是正确的。 - Kyle Ivey
我已经尝试了很多技巧,包括引用的例子,即定义任意 TypedValue.COMPLEX_UNIT_DIP, 5。最终,这是唯一有效的方法,可以对齐不同文本大小的2个TextView,而没有任何奇怪的数字。如果可以的话,我会给你+10分 :) - Henrique de Sousa

3
我想补充一下 DynamicMind 的回答,你看到 TextView 周围有间距是因为它们默认使用的 9-patch 背景中有填充。9-patch 技术允许您指定一个内容区域,实际上就是填充。除非您显式地设置视图的填充,否则将使用该填充。例如,当您以编程方式将 9-patch 背景设置为具有填充设置的视图时,它们将被覆盖。反之亦然,如果您设置了填充,则会覆盖 9-patch 背景设置的内容。
不幸的是,在 XML 布局中无法确定这些操作的顺序。我认为只需从 TextView 中移除背景即可解决问题:
android:background="@null"

这就解释了为什么我的xml中有我没有设置的填充。必须设置padding=5dp来覆盖9 patch背景的默认填充。谢谢。 - Daniel Storch

2
public class TopAlignedTextView extends TextView {

    public TopAlignedTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TopAlignedTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs);
        setIncludeFontPadding(false); //remove the font padding
        setGravity(getGravity() | Gravity.TOP);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        TextPaint textPaint = getPaint();
        textPaint.setColor(getCurrentTextColor());
        textPaint.drawableState = getDrawableState();
        canvas.save();

        //remove extra font padding
        int yOffset = getHeight() - getBaseline();
        canvas.translate(0, - yOffset / 2);

        if (getLayout() != null) {
            getLayout().draw(canvas);
        }
        canvas.restore();
    }
}

2

稍微修改了这个答案,使用kotlin类并扩展AppCompatTextView,修剪垂直填充。

它允许设置android:fontFamily。方法calculateTextParams()onDraw()中移动以提高性能。未针对多行文本进行测试:

import android.content.Context
import android.graphics.Canvas
import android.graphics.Rect
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView

class NoPaddingTextView : AppCompatTextView
{
  private val boundsRect = Rect()
  private val textParams = calculateTextParams()

  constructor(context : Context?)
  : super(context)

  constructor(context : Context?, attrs : AttributeSet?)
  : super(context, attrs)

  constructor(context : Context?, attrs : AttributeSet?, defStyleAttr : Int)
  : super(context, attrs, defStyleAttr)

  override fun onDraw(canvas : Canvas)
  {
    with(boundsRect) {
      paint.isAntiAlias = true
      paint.color = currentTextColor
      canvas.drawText(textParams,
                      -left.toFloat(),
                      (-top - bottom).toFloat(),
                      paint)
    }
  }

  override fun onMeasure(widthMeasureSpec : Int, heightMeasureSpec : Int)
  {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    calculateTextParams()
    setMeasuredDimension(boundsRect.width() + 1, -boundsRect.top + 1)
  }

  private fun calculateTextParams() : String
  {
    return text.toString()
    .also {text ->
      text.length.let {textLength ->
        paint.textSize = textSize
        paint.getTextBounds(text, 0, textLength, boundsRect)
        if(textLength == 0) boundsRect.right = boundsRect.left
      }
    }
  }
}

1
你定义了布局边距吗? 例如:
android:layout_marginTop="5dp"

否则,如果您的文本视图被包装在LinearLayout或其他容器中,则该容器可能也具有填充或边距。

0
android:background="@android:drawable/editbox_background"

根据您的需求使用它,更改您想要的editbox_background。 因为Android提供了一些内置的背景,像上面的代码一样选择适合您的要求。 也许对您有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接