Android: TextView: Remove spacing and padding on top and bottom
When I have a TextView
with a \n
in the text,, on the right I have two singleLine
TextView
s, one below the other with no spacing in between. I have set the following for all three TextView
s.
android:lineSpacingMultiplier="1"
android:lineSpacingExtra="0pt"
android:pa开发者_开发知识库ddingTop="0pt"
android:paddingBottom="0pt"
The first line of the left TextView
lines up perfectly with the top right TextView
.
The second line of the left TextView
is a little higher than the second line of the bottom right TextView
.
It seems that there is some kind of hidden padding on the top and the bottom of the TextView
s. How can I remove that?
setIncludeFontPadding (boolean includepad)
or in XML
this would be:
android:includeFontPadding="false"
Set whether the TextView
includes extra top and bottom padding to make room for accents that go above the normal ascent and descent. The default is true.
I searched a lot for proper answer but no where I could find an Answer which could exactly remove all the padding from the TextView
, but finally after going through the official doc got a work around for Single Line Texts
android:includeFontPadding="false"
android:lineSpacingExtra="0dp"
Adding these two lines to TextView
xml will do the work.
First attribute removes the padding reserved for accents and second attribute removes the spacing reserved to maintain proper space between two lines of text.
Make sure not to add
lineSpacingExtra="0dp"
in multiline TextView as it might make the appearance clumsy
I feel your pain. I've tried every answer above, including the setIncludeFontPadding
to false, which did nothing for me.
My solution? layout_marginBottom="-3dp"
on the TextView
gives you a solution for the bottom,
BAM!
Although, -3dp on layout_marginTop
fails....ugh.
You can try to use this attribute(ConstraintLayout):layout_constraintBaseline_toBaselineOf
Like this:
app:layout_constraintBaseline_toBaselineOf="@+id/textView"
Updated XML
android:fontFamily="monospace"
android:includeFontPadding="false"
If you use AppCompatTextView
( or from API 28
onward ) you can use the combination of those 2 attributes to remove the spacing on the first line:
XML
android:firstBaselineToTopHeight="0dp"
android:includeFontPadding="false"
Kotlin
text.firstBaselineToTopHeight = 0
text.includeFontPadding = false
Add android:includeFontPadding="false" to see if it helps.And make text view size same as that of text size rather than "wrap content".It will definitely work.
This annoyed me too, and the answer I found was that there is actually additional space in the font itself, not the TextView. It is rather irritating, coming from a document publishing background, the limited amount of control you have with Android over typographic elements. I'd recommend using a custom typeface (such as Bitstream Vera Sans, which is licensed for redistribution) that may not have this issue. I'm not sure specifically whether or not it does, though.
I remove the spacing in my custom view -- NoPaddingTextView.
https://github.com/SenhLinsh/NoPaddingTextView
package com.linsh.nopaddingtextview;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.widget.TextView;
/**
* Created by Senh Linsh on 17/3/27.
*/
public class NoPaddingTextView extends TextView {
private int mAdditionalPadding;
public NoPaddingTextView(Context context) {
super(context);
init();
}
public NoPaddingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
setIncludeFontPadding(false);
}
@Override
protected void onDraw(Canvas canvas) {
int yOff = -mAdditionalPadding / 6;
canvas.translate(0, yOff);
super.onDraw(canvas);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
getAdditionalPadding();
int mode = MeasureSpec.getMode(heightMeasureSpec);
if (mode != MeasureSpec.EXACTLY) {
int measureHeight = measureHeight(getText().toString(), widthMeasureSpec);
int height = measureHeight - mAdditionalPadding;
height += getPaddingTop() + getPaddingBottom();
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private int measureHeight(String text, int widthMeasureSpec) {
float textSize = getTextSize();
TextView textView = new TextView(getContext());
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
textView.setText(text);
textView.measure(widthMeasureSpec, 0);
return textView.getMeasuredHeight();
}
private int getAdditionalPadding() {
float textSize = getTextSize();
TextView textView = new TextView(getContext());
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
textView.setLines(1);
textView.measure(0, 0);
int measuredHeight = textView.getMeasuredHeight();
if (measuredHeight - textSize > 0) {
mAdditionalPadding = (int) (measuredHeight - textSize);
Log.v("NoPaddingTextView", "onMeasure: height=" + measuredHeight + " textSize=" + textSize + " mAdditionalPadding=" + mAdditionalPadding);
}
return mAdditionalPadding;
}
}
Since my requirement is override the existing textView get from findViewById(getResources().getIdentifier("xxx", "id", "android"));
, so I can't simply try onDraw()
of other answer.
But I just figure out the correct steps to fixed my problem, here is the final result from Layout Inspector:
Since what I wanted is merely remove the top spaces, so I don't have to choose other font to remove bottom spaces.
Here is the critical code to fixed it:
Typeface mfont = Typeface.createFromAsset(getResources().getAssets(), "fonts/myCustomFont.otf");
myTextView.setTypeface(mfont);
myTextView.setPadding(0, 0, 0, 0);
myTextView.setIncludeFontPadding(false);
The first key is set custom font "fonts/myCustomFont.otf" which has the space on bottom but not on the top, you can easily figure out this by open otf file and click any font in android Studio:
As you can see, the cursor on the bottom has extra spacing but not on the top, so it fixed my problem.
The second key is you can't simply skip any of the code, otherwise it might not works. That's the reason you can found some people comment that an answer is working and some other people comment that it's not working.
Let's illustrated what will happen if I remove one of them.
Without setTypeface(mfont);
:
Without setPadding(0, 0, 0, 0);
:
Without setIncludeFontPadding(false);
:
Without 3 of them (i.e. the original):
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/baselineImage"
android:includeFontPadding="false" />
<ImageView
android:id="@+id/baselineImage"
android:layout_width="1dp"
android:layout_height="1dp"
android:baselineAlignBottom="true"
android:layout_alignParentBottom="true" />
<!-- This view will be exactly 10dp below the baseline of textView -->
<View
android:id="@+id/view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_below="@+id/baselineImage" />
</RelativeLayout>
With an extra ImageView we can set the TextView to be baseline aligned with the ImageView and set the android:baselineAlignBottom
on the ImageView to true, which will make the baseline of ImageView to bottom. Other views can align itself using the bottom of the ImageView which itself is the same as the TextView's baseline.
This however only fixes the padding bottom not the top.
I think this problem can be solved in this way:
<TextView
android:id="@+id/leftText"
android:includeFontPadding="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30dp"
android:text="Hello World!\nhello world" />
<TextView
android:id="@+id/rightUpperText"
android:includeFontPadding="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/leftText"
android:layout_alignTop="@+id/leftText"
android:textSize="30dp"
android:text="Hello World!" />
<TextView
android:id="@+id/rightLowerText"
android:includeFontPadding="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/leftText"
android:layout_below="@+id/rightUpperText"
android:textSize="30dp"
android:text="hello world" />
Those are the results:
ScreenShot-1
ScreenShot-3
Though the line of special characters in rightLowerText looks a little bit higher than the second line of leftText, their baselines are stilled aligned.
Simple method worked:
setSingleLine();
setIncludeFontPadding(false);
If it not worked, then try to add this above that code:
setLineSpacing(0f,0f);
// and set padding and margin to 0
If you need multi line, maybe you'll need to calculate exactly the height of padding top and bottom via temp single line TextView (before and after remove padding) , then apply decrease height result with negative padding or some Ghost Layout with translate Y. Lol
Only thing that worked is
android:lineSpacingExtra="-8dp"
You might want to try aligning the bottom of the left text view with the bottom of the 2nd right text view.
To my knowledge this is inherent to most widgets and the amount of "padding" differs among phone manufacturers. This padding is really white space between the image border and the image in the 9 patch image file.
For example on my Droid X, spinner widgets get extra white space than buttons, which makes it look awkward when you have a spinner inline with a button, yet on my wife's phone the same application doesn't have the same problem and looks great!
The only suggestion I would have is to create your own 9 patch files and use them in your application.
Ahhh the pains that are Android.
Edited: Clarify padding vs white space.
This trick worked for me (for min-sdk >= 18).
I used android:includeFontPadding="false"
and a negative margin like android:layout_marginTop="-11dp"
and put my TextView
inside a FrameLayout
( or any ViewGroup...)
and finally sample codes:
<LinearLayout
android:layout_width="60dp"
android:layout_height="wrap_content"
>
<TextView
style="@style/MyTextViews.Bold"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/yellow"
android:textSize="48sp"
android:layout_marginTop="-11dp"
android:includeFontPadding="false"
tools:text="1"/>
</LinearLayout>
Use constraintlayout as your root view then add a guideline helper.
Example:
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/guideline" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="20dp" />
Attribute layout_constraintGuide_begin value is just example, it depend on your needs.
You can partially resolve this with some of the hacks listed here (negative margins, font padding, etc), but you can't get around the size of the font itself[1]. The fixed height of each "cell" of a font must be large enough to accommodate the tallest character, in all languages.
If you employ the hacks listed in other answers the font can be clipped.
The solution is to explain to your designers that this is how fonts are packaged, and to have them account for this in their designs. Don't hack things up now to have bugs filed down the road when it's translated to other languages.
[1] I suppose one could package their own fonts with compacted ascenders and descenders.
This worked for me:
android:minHeight="0dp"
You can try to use this attribute(ConstraintLayout): layout_constraintBaseline_toBaselineOf
See this:
Align ImageView with EditText horizontally
It seems that the background image of EditText has some transparent pixels which also add padding.
A solution is to change the default background of EditText to something else (or nothing, but no background for a EditText is probably not acceptable). That's can be made setting android:background XML attribute.
android:background="@drawable/myEditBackground"
Use this in your ImageView xml
android:adjustViewBounds="true"
精彩评论