java - Android TextView 中真正的顶部对齐文本

标签 java android textview vertical-alignment

我正在尝试显示 TextView在 Android 中, View 中的文本是顶部对齐的:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Create container layout
    FrameLayout layout = new FrameLayout(this);

    // Create text label
    TextView label = new TextView(this);
    label.setTextSize(TypedValue.COMPLEX_UNIT_PX, 25);     // 25 pixels tall
    label.setGravity(Gravity.TOP + Gravity.CENTER);        // Align text top-center
    label.setPadding(0, 0, 0, 0);                          // No padding
    Rect bounds = new Rect();
    label.getPaint().getTextBounds("gdyl!", 0, 5, bounds); // Measure height
    label.setText("good day, world! "+bounds.top+" to "+bounds.bottom);
    label.setTextColor      (0xFF000000);                  // Black text
    label.setBackgroundColor(0xFF00FFFF);                  // Blue background

    // Position text label
    FrameLayout.LayoutParams layoutParams = 
            new FrameLayout.LayoutParams(300, 25, Gravity.LEFT + Gravity.TOP);
                                                            // also 25 pixels tall
    layoutParams.setMargins(50, 50, 0, 0);
    label.setLayoutParams(layoutParams);

    // Compose screen
    layout.addView(label);
    setContentView(layout);
}

此代码输出以下图像:

enter image description here

注意事项:

  • 蓝色框高 25 像素,与要求的一样
  • 文本边界也按要求报告为 25 像素高 (6 - (-19) = 25)
  • 文本不是从标签的顶部开始,而是在其上方有一些填充,忽略 setPadding()
  • 这会导致文本在底部被剪裁,即使从技术上讲盒子足够高

如何让 TextView 在框的最顶部开始显示文本?

我对可能的答案有两个限制:

  • 不过,我确实需要使文本保持顶部对齐,所以如果有一些技巧可以将其底部对齐或垂直居中,我就无法使用它,因为我遇到了 TextView 比它高的情况需要。
  • 我有点兼容性狂,所以如果可能的话,我想坚持使用早期 Android API 中可用的调用(最好是 1,但绝对不超过 7)。

最佳答案

TextViews使用抽象类 android.text.Layoutdraw the text在 Canvas 上:

canvas.drawText(buf, start, end, x, lbaseline, paint);

垂直偏移 lbaseline 计算为行的底部减去字体的下降:

int lbottom = getLineTop(i+1);
int lbaseline = lbottom - getLineDescent(i);

getLineTopgetLineDescent 这两个调用函数是抽象的,但是可以在BoringLayout 中找到一个简单的实现。 (看图...:),它只返回 mBottommDesc 的值。这些是在其 init 中计算的方法如下:

if (includepad) {
    spacing = metrics.bottom - metrics.top;
} else {
    spacing = metrics.descent - metrics.ascent;
}

if (spacingmult != 1 || spacingadd != 0) {
    spacing = (int)(spacing * spacingmult + spacingadd + 0.5f);
}

mBottom = spacing;

if (includepad) {
    mDesc = spacing + metrics.top;
} else {
    mDesc = spacing + metrics.ascent;
}

此处,includepad 是一个 boolean 值,它指定文本是否应包含额外的填充以允许超出指定上升沿的字形。它可以由 TextView 的 setIncludeFontPadding 设置(正如@ggc 指出的那样)方法。

如果 includepad 设置为 true(默认值),则文本定位在 top-field 给定的基线处。字体的指标。否则文本的基线取自 descent-field .

因此,从技术上讲,这应该意味着我们需要做的就是关闭 IncludeFontPadding,但不幸的是,这会产生以下结果:

enter image description here

这样做的原因是字体报告其上升为 -23.2,而边界框报告的最高值为 -19。我不知道这是字体中的“错误”还是应该是这样的。不幸的是,FontMetrics 不提供任何与边界框报告的 19 相匹配的值,即使您尝试以某种方式将报告的 240dpi 屏幕分辨率与 72dpi 的字体点定义相结合,因此没有“官方”方式来解决这个问题。

但是,当然,可用信息可用于破解解决方案。有两种方法:

  • 单独使用 IncludeFontPadding,即设置为 true:

    double top = label.getPaint().getFontMetrics().top;
    label.setPadding(0, (int) (top - bounds.top - 0.5), 0, 0);
    

    即设置垂直填充以补偿文本边界报告的 y 值与字体度量的最高值之​​间的差异。结果:

    enter image description here

  • 将 IncludeFontPadding 设置为 false:

    double ascent = label.getPaint().getFontMetrics().ascent;
    label.setPadding(0, (int) (ascent - bounds.top - 0.5), 0, 0);
    label.setIncludeFontPadding(false);
    

    即设置垂直填充以补偿文本边界报告的 y 值与字体度量的上升值之间的差异。结果:

    enter image description here

请注意,将 IncludeFontPadding 设置为 false 并没有什么神奇之处。 两个版本应该都可以。它们产生不同结果的原因是当字体度量的浮点值转换为整数时舍入误差略有不同。碰巧在这种特殊情况下,将 IncludeFontPadding 设置为 false 看起来更好,但对于不同的字体或字体大小,这可能会有所不同。调整顶部填充的计算以产生与 BoringLayout 使用的计算相同的精确舍入误差可能相当容易。我还没有这样做,因为我宁愿使用“无错误”字体,但如果我有时间,我可能会稍后添加它。那么,IncludeFontPadding 是设置为 false 还是 true 应该是真正无关紧要的。

关于java - Android TextView 中真正的顶部对齐文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26680079/

相关文章:

java - 将 SQL 数据引入 jquery availabletag

java - 在 Web 容器内部,如何创建/管理具有相同引用变量的同一类的多个对象

android:在 TextView 中使用 <a href> 设置链接

java - 区分相同的数组列表

java - 在 JPA (EclipseLink) 中有一个类似 @Formula 的注释来设置来自子查询的计算字段?

Android ListView展开项目列表

Android - 传递图像资源整数

android - 创建一个扩展 API 25+ 资源的类

android - 在android中创建一个类似纸的折叠 View

android - 如何将TextView背景颜色更改为初始值