66

When I include the below XML to layout file, I can see the below image. If you see it, you could realize that the TextView has top and bottom space.

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

enter image description here

I wish to remove the space. How to remove it? What is it called? If anyone has clue.. please let me know. Thanks in advance.

Denis Dmitrienko
  • 1,532
  • 2
  • 16
  • 26
mooongcle
  • 3,987
  • 5
  • 33
  • 42
  • Possible duplicate of [Android: TextView: Remove spacing and padding on top and bottom](http://stackoverflow.com/questions/4768738/android-textview-remove-spacing-and-padding-on-top-and-bottom) – Mohammed Atif Oct 19 '16 at 11:47

14 Answers14

99

Try android:includeFontPadding="false" to see if it helps. In my experience that will help a little bit, but there's no way of reducing the TextView dimensions to the exact pixel-perfect text size.

The only alternative, which may or may not give better results, is to cheat a bit and hard-wire the dimensions to match the text size, e.g. "24sp" instead of "wrap_content" for the height.

Graham Borland
  • 60,055
  • 21
  • 138
  • 179
32

I had the same problem. Attribute android:includeFontPadding="false" does not work for me. I've solved this problem in this way:

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;
    }
}
Anton
  • 560
  • 6
  • 21
  • 2
    great solution! tried with different text size and worked like charm :) – dakshbhatt21 Jun 08 '16 at 14:10
  • 2
    update: in above code, when I use q, g, y, p in lower case they got cut from bottom. So for that change `setMeasuredDimension(mBounds.width() + 1, -mBounds.top + 1);` to `setMeasuredDimension(mBounds.width() + 1, -mBounds.top + mBounds.bottom);` – dakshbhatt21 Jun 09 '16 at 11:20
  • looks like performance-wise it's not great idea to call calculateTextParams in onDraw(). – sandrstar Mar 16 '17 at 09:09
  • 4
    Works. But if you specify android:fontFamily, then change mPaint to getPaint(), otherwise fontFamily is not applied. – YetAnotherUser May 04 '17 at 14:58
  • Didn't work for me. It trimmed the padding, but the font was centered to it cut out most of the font as well. Was using a large font (56sp) if that makes a difference. – Jeffrey Blattman Jun 12 '17 at 21:52
  • It works with a single line but, when I add multiple lines using "\n" it is showing in just a single line. – VIISHRUT MAVANII Jan 10 '20 at 09:34
24

android:includeFontPadding="false" is pretty good but it does not get it precisely. sometimes you want border line accuracy so you can figure it out yourself by applying negative margins:

try setting your bottom and top margins to a negative value.

something like this:

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

adjust the values accordingly.

j2emanue
  • 60,549
  • 65
  • 286
  • 456
5

This is the code that saved our day. It was adapted using mono C# code from maksimko:

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);
    }
}

Still had to play around with textView.setIncludeFontPadding(false) because we were aligning TextViews with different font sizes.

Henrique de Sousa
  • 5,727
  • 49
  • 55
4

I faced the same problem. Here's a good answer: How to align the text to top of TextView?

But code is little unfinished and don't support all font sizes. Change the line

int additionalPadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getContext().getResources().getDisplayMetrics());

to

int additionalPadding = getTextSize() - getLineHeight();

Complete C# code (mono) removes top offset:

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 ();
    }
}
Community
  • 1
  • 1
  • The example referenced inverts the translation amount at the last moment, this code does not. Solution is correct otherwise. – Kyle Ivey Aug 21 '13 at 02:32
  • I have tried a lot of hacks, including the example referenced that defined the arbitrary `TypedValue.COMPLEX_UNIT_DIP, 5`. Finally, this is the only one that works in order to align 2 TextViews of different textSizes, without any magic number whatsoever. I would give you +10 if I could :) – Henrique de Sousa Oct 24 '14 at 21:10
3

Just wanted to add to DynamicMind's answer that the reason why you see spacing around your TextViews is padding in 9-patch backgrounds they use by default.

9-patch technology allows you to specify a content area which is, effectively, padding. That padding is used unless you set the view's padding explicitly. E.g., when you programmatically set a 9-patch background to a view which had paddings set, they are overridden. And vise-versa, if you set paddings they override what was set by 9-patch background.

Unfortunately, in the XML layout it's not possible to determine the order of these operations. I think just removing the background from your TextViews would help:

android:background="@null"
Community
  • 1
  • 1
JBM
  • 2,930
  • 2
  • 24
  • 28
  • This explains why i had padding i didn't set in my xml. Had to set padding=5dp to override the default padding form 9 patch background. Thanks – Daniel Storch Jan 13 '15 at 16:56
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();
    }
}
josliber
  • 43,891
  • 12
  • 98
  • 133
minal sharma
  • 189
  • 1
  • 1
  • 4
2

Modified this answer a little bit to use kotlin class and extend AppCompatTextView, trimming vertical padding.

It allows setting android:fontFamily. Method calculateTextParams() moved from onDraw() for performance. Not tested for multiple lines of text:

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
      }
    }
  }
}
Denis Dmitrienko
  • 1,532
  • 2
  • 16
  • 26
1

Have you defined a layout margin? For example:

android:layout_marginTop="5dp"

Otherwise, if your text view is wrapped inside a LinearLayout or other container, then that cold have either padding or a margin too.

Todd Davies
  • 5,484
  • 8
  • 47
  • 71
0

Inside a LinearLayout the default padding might be an issue. Try setting it to 0dp. It worked for me.

kjoelbro
  • 6,296
  • 4
  • 21
  • 18
0

The answer of TopAlignedTextView code:TopAlignedTextView@GitHub

use it by layout:

<com.github.captain_miao.view.TopAlignedTextView
    android:id="@+id/text_a"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:text="@string/text_demo_a"
/>

enter image description here

Community
  • 1
  • 1
qinmiao
  • 5,559
  • 5
  • 36
  • 39
0

My way for fixing this is pretty hacky, but I managed to get the text to sit where I wanted by setting the height of the text view as static and fiddling with it until it just barely fit the text. In my case, the font style I was using had a height of 64sp so I set the height of my textview to 50sp and it worked okay. I also had to set foreground_gravity to bottom.

kjanderson2
  • 1,209
  • 12
  • 23
0
android:background="@android:drawable/editbox_background"

use it according to you change it that you want editbox_background. because android provide some build in background like above code choose according to your requirement. May be it is help full to you.

DynamicMind
  • 4,240
  • 1
  • 26
  • 43
-1
android:includeFontPadding="false"
Appnweb31
  • 74
  • 3
  • Your answer could be improved by adding more information on what the code does and how it helps the OP. – Tyler2P Oct 01 '22 at 17:26