9

我试图通过将负“添加”设置为 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”):

减小行距会在底线削减“g”

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

 android:layout_height="fill_parent"

它确实正确渲染:

使用 'fill_parent' 不会截断底线

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

4

7 回答 7

10

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

}
于 2013-06-10T14:01:04.200 回答
6

我遇到了同样的问题,但是当我尝试使用小于 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);
    }

}
于 2012-11-14T19:49:28.633 回答
1

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

虽然我觉得这个值应该包含在 onMeasure 方法中,但您始终可以测量所需的确切高度,然后进行简单检查:

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

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

希望能帮助到你。

于 2012-08-13T10:06:45.847 回答
1

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

机器人:lineSpacingMultiplier="0.8"

**

于 2017-10-31T15:19:55.827 回答
0

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

于 2012-08-12T17:37:21.440 回答
0

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

于 2012-08-12T20:33:54.623 回答
0

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

布局:

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

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

在此处输入图像描述

于 2012-08-12T22:02:48.430 回答