由于UI的奇葩作图稿,要求文字要贴边,否则会导致上下的View的margin会变大(因为TextView的文字绘制时有上下间距)。
Paint.FontMetrics
/**
* Class that describes the various metrics for a font at a given text size.
* Remember, Y values increase going down, so those values will be positive,
* and values that measure distances going up will be negative. This class
* is returned by getFontMetrics().
*/
public static class FontMetrics {
/**
* The maximum distance above the baseline for the tallest glyph in
* the font at a given text size.
*/
public float top;
/**
* The recommended distance above the baseline for singled spaced text.
*/
public float ascent;
/**
* The recommended distance below the baseline for singled spaced text.
*/
public float descent;
/**
* The maximum distance below the baseline for the lowest glyph in
* the font at a given text size.
*/
public float bottom;
/**
* The recommended additional space to add between lines of text.
*/
public float leading;
}
Baseline是基线,在Android中,文字的绘制都是从Baseline处开始的,Baseline往上至字符“最高处”的距离我们称之为ascent(上坡度),Baseline往下至字符“最低处”的距离我们称之为descent(下坡度);
leading(行间距)则表示上一行字符的descent到该行字符的ascent之间的距离;
-
TextView在绘制文本的时候总会在文本的最外层留出一些内边距,为什么要这样做?因为TextView在绘制文本的时候考虑到了类似读音符号,看下图中的A上面的符号。
一般情况下我们极少使用到类似的符号所以往往会忽略掉这些符号的存在,但是Android依然会在绘制文本的时候在文本外层留出一定的边距,这就是为什么top和bottom总会比ascent和descent大一点的原因。而在TextView中我们可以通过xml设置其属性android:includeFontPadding="false"去掉一定的边距值但是不能完全去掉。
无边距TextView
public class NoPaddingTextView extends AppCompatTextView {
public NoPaddingTextView(Context context) {
this(context, null);
}
public NoPaddingTextView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public NoPaddingTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.NoPaddingTextView, 0, 0);
int textSize = a.getDimensionPixelSize(R.styleable.NoPaddingTextView_textSize, (int) TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12, getResources().getDisplayMetrics()));
Paint paint = new Paint();
Log.e("NoPaddingTextView", "textSize:" + textSize);
paint.setTextSize(textSize);
final Paint.FontMetricsInt fontMetricsInt = paint.getFontMetricsInt();
setTextSize(TypedValue.COMPLEX_UNIT_PX, a.getDimension(R.styleable.NoPaddingTextView_textSize, 12));
int top = (int) Math.ceil(Math.abs((fontMetricsInt.top - fontMetricsInt.ascent) / 2.0));
Log.e("NoPaddingTextView", "top" + top);
setPadding(0, -(Math.abs(fontMetricsInt.top - fontMetricsInt.ascent) + top)
, 0,
fontMetricsInt.top - fontMetricsInt.ascent);
a.recycle();
post(new Runnable() {
@Override
public void run() {
Log.e("NoPaddingTextView", "getHeight()" + getHeight());
}
});
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
}
//attr
<declare-styleable name="NoPaddingTextView">
<attr name="textSize" format="dimension" />
</declare-styleable>
比较
注意,在post中调用Log.e("NoPaddingTextView", "getHeight()" + getHeight());输入height和textSize的px一致。