【问题标题】:How to reduce TextView line spacing如何减少 TextView 行距
【发布时间】:2012-08-12 17:33:45
【问题描述】:

我正在尝试通过为 TextView.setLineSpacing() 设置负“添加”来减少 TextView 中的行间距。它运作良好,只是底线被截断。

主布局

<TextView
    android:id="@+id/text_view"
    android:padding="dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    tools:context=".MainActivity" />

主要活动:(注意

package com.font_test;

import android.app.Activity;
import android.graphics.Typeface;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/custom_fonts.ttf");
        final TextView tv = (TextView) findViewById(R.id.text_view);
        tv.setTypeface(typeface);
        tv.setTextSize(60);
        tv.setLineSpacing(-30f, 1f);  // *** -30 to reduce line spacing
        tv.setBackgroundColor(0x280000ff);
        tv.setText("gggkiiikkk" + "\n" + "gikgikgik" + "\n" + "kigkigkig");
    }
}

这会导致视图底部被截断(注意底部的“g”):

问题似乎与不正确的布局测量有关。如果我将 TextView 设置为

 android:layout_height="fill_parent"

它确实呈现正确:

知道如何解决吗?如果有帮助,我不介意有丑陋的解决方法。我还可以访问 FontForge,如果需要,我可以修改字体文件。

【问题讨论】:

  • 内置字体也会发生这种情况吗?或者任何其他自定义字体?可能是字体没有报告正确的下降值。
  • 最后一行LineSpacing of -30f 正在申请。这就是为什么最后一行没有正确看到的原因。所以你可以set bottom padding of 30 在你的情况下...@kcoppock 我认为descent values没有任何问题
  • @kcoppock,我遇到了同样的问题 typeface = Typeface.SANS_SERIF;
  • @Mohsin,添加 android:paddingBottom="60dp" 在底部添加了边距,但字体仍被截断。见imgur.com/du5xJ

标签: android fonts textview truetype


【解决方案1】:

littleFluffyKittys 的回答很好,但如果行距是通过 xml 设置的,它在某些设备上不起作用

我通过比较字体的原始高度和 textview 为一行计算的高度来计算所需的额外高度。 如果行高小于字体的高度,则差异增加一次。

这至少可以降低 API 10(只是没有测试过更低)

public class ReducedLineSpacingTextView extends TextView {

    public ReducedLineSpacingTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int truncatedHeight = getPaint().getFontMetricsInt(null) - getLineHeight();
        if (truncatedHeight > 0) {
            setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() + truncatedHeight);
        }
    }

}

【讨论】:

  • 这是最好的解决方案。
  • 如果我需要以编程方式减小行距,即 setLineSpacing(float, float) 在您的解决方案中的什么位置?
【解决方案2】:

我遇到了同样的问题,但是当我尝试使用小于 1 的间距乘数时。

我创建了TextView 的子类,它自动修复最后一行的截断,并且不需要您在底部设置已知/固定间距。

只要使用这个类就可以正常使用了,不需要额外加间距或修正。

public class ReducedLineSpacingTextView extends TextView {

    private boolean mNegativeLineSpacing = false;

    public ReducedLineSpacingTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mNegativeLineSpacing) { // If you are only supporting Api Level 16 and up, you could use the getLineSpacingExtra() and getLineSpacingMultiplier() methods here to check for a less than 1 spacing instead.
            Layout layout = getLayout();
            int truncatedHeight = layout.getLineDescent(layout.getLineCount()-1);
            setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() + truncatedHeight);
        }
    }

    @Override
    public void setLineSpacing(float add, float mult) {
        mNegativeLineSpacing = add < 0 || mult < 1;
        super.setLineSpacing(add, mult);
    }

}

【讨论】:

    【解决方案3】:

    不错! 这样就可以了,但是将常量值放在我们有变量的任何地方都不是一个好主意。您可以使用 lineSpacing 值以 dinamyc 的方式将它们添加到 onMeasure 方法。 请注意,此值始终可通过“getLineSpacingExtra()”和“getLineSpacingMultiplier()”获得。或者更容易得到两者的值:“getLineHeight()”。

    虽然我觉得这个值应该包含在onMeasure方法中,但是你总是可以测量出你需要的准确高度,然后做一个简单的检查:

    final int measuredHeight = getMeasuredHeight();
    if (measuredHeight < neededHeight) {
        setMeasuredDimension(getMeasuredWidth, neededHeight);   
    }
    

    最后一件事,您不需要在单独的属性中传递上下文。如果您查看构造函数,则上下文已经存在。如果您需要组件的代码,您可以使用“getContext()”。

    希望对你有帮助。

    【讨论】:

      【解决方案4】:

      使用它来减少文本视图中的行距 **

      android:lineSpacingMultiplier="0.8"

      **

      【讨论】:

        【解决方案5】:

        如果填充不起作用,边距应该可以完成工作。如果您仍然有问题,您可以随时将行距值应用于视图的 onMeasure 方法。您必须为此创建一个 custom component 并扩展 onMeasure。

        【讨论】:

        • 将 android:layout_margin="20dp" 或 android:layout_marginBottom="20dp" 添加到 TextView 没有帮助。最后一行仍然被截断。我认为边距是由父视图添加的,在 TextView 确定其所需的度量之后。我也会尝试你的自定义组件建议。
        • 谢谢何塞。自定义组件的想法似乎奏效了。在这里查看我自己的答案。将您的答案标记为正确答案。
        • 我发布了一些修复此错误的 TextView 代码。希望能帮助到你。 stackoverflow.com/a/13386208/445348
        • 这不是问题的解决方案,实际上下面有一个更好的解决方案。
        【解决方案6】:

        只需将 paddingBottom 添加到您的 TextView xml 的声明中,选择一个产生良好结果的值。并因此为其他填充(顶部、让和右侧)设置值。这应该可以解决您的问题

        【讨论】:

        • 将 android:paddingBottom="60dp" 添加到 TextView 添加填充但底线字体仍被截断。见imgur.com/du5xJ
        【解决方案7】:

        这是我根据 Jose 在此处的回答所做的,它似乎有效。我对布局机制的复杂性不是很熟悉。这段代码安全吗?有什么问题吗?

        布局:

        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
        
            <com.font_test.MyTextView
                android:id="@+id/text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                tools:context=".MainActivity" />
        
        </RelativeLayout>
        

        添加了将垂直高度扩展 N 个像素的自定义 TextView:

        package com.font_test;
        
        import android.content.Context;
        import android.util.AttributeSet;
        import android.widget.TextView;
        
        public class MyTextView extends TextView {
        
            public MyTextView(Context context, AttributeSet attrs) {
                super(context, attrs);
            }
        
            @Override
            protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                // TODO: provide an API to set extra bottom pixels (50 in this example)
                setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() + 50);       
            }
        }
        

        底部不截断的结果文本视图渲染:

        【讨论】:

        • 这对你真的有用吗?对我来说,它的作用与底部填充相同 - 为 textview 添加空间,但最后一行仍被剪裁
        猜你喜欢
        • 1970-01-01
        • 2020-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-11
        • 2015-04-02
        • 1970-01-01
        相关资源
        最近更新 更多