9

TextView.setLineSpacing() に負の 'add' を設定して、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 が行に対して計算する高さとを比較して、必要な追加の高さを計算します。行の高さがフォントの高さよりも小さい場合、差分は 1 回追加されます。

これは、少なくとも 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 値を使用して、ダイナミックな方法で onMeasure メソッドに追加できます。この値は、「getLineSpacingExtra()」および「getLineSpacingMultiplier()」を通じて常に使用できることに注意してください。または、「getLineHeight()」のように、両方の合計値を簡単に取得できます。

この値を onMeasure メソッドに含める必要があるように感じますが、必要な正確な高さをいつでも測定して、簡単なチェックを行うことができます。

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

最後に、別の属性でコンテキストを渡す必要はありません。コンストラクタを見ると、コンテキストはすでにそこにあります。コンポーネントのコードに沿って必要な場合は、「getContext()」を使用できます。

それが役に立てば幸い。

于 2012-08-13T10:06:45.847 に答える
0

TextView xmlの宣言にpaddingBottomを追加し、適切な結果が得られる値を選択するだけです。その結果、他のパディング(top、let、right)の値を設定します。これで問題が解決するはずです

于 2012-08-12T17:37:21.440 に答える
0

これは、Jose's answer here に基づいて私が行ったことであり、うまくいくようです。私は複雑なレイアウト メカニズムにあまり詳しくありません。このコードは安全ですか? 何か問題はありますか?

レイアウト:

<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 に答える
0

パディングが機能しない場合は、マージンが仕事をする必要があります。それでも問題が解決しない場合は、いつでも行間隔の値をビューの onMeasure メソッドに適用できます。そのためのカスタム コンポーネントを作成し、onMeasure を拡張する必要があります。

于 2012-08-12T20:33:54.623 に答える