2012-08-12 126 views
7

我想通过设置一个负面的'添加到TextView.setLineSpacing()来减少TextView中的行间距。除了底线被截断之外,它运作良好。如何减少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'在底线):

Reducing the line spacing cuts the 'g' at the bottom line

看来问题与不正确的布局测量有关。如果我设置的TextView到

android:layout_height="fill_parent" 

它无法正确显示:

Using 'fill_parent' does not truncate the bottom line

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

+0

是否发生内置的字体呢?或者其他任何自定义字体?这可能是因为字体没有报告正确的下降值。最后一行的 – kcoppock 2012-08-12 17:37:26

+1

也是'LineSpacing of -30f'正在应用。这就是为什么最后一行看不到的原因。所以你可以在你的情况下设置30的底部填充... @ kcoppock我认为在'descent values'中没有任何错误' – 2012-08-12 17:43:27

+0

@kcoppock,我得到了与typeface = Typeface.SANS_SERIF相同的问题; – user1139880 2012-08-12 21:24:50

回答

0

如果填充不起作用,保证金应该做的工作。如果仍有问题,则可以将行间距值始终应用于视图的onMeasure方法。您必须为此创建一个custom component并扩展onMeasure。

+0

向TextView添加android:layout_margin =“20dp”或android:layout_marginBottom =“20dp”并没有帮助。最后一行仍然被截断。我认为在TextView确定了所需的度量之后,边距由父视图添加。我也会尝试你的自定义组件建议。 – user1139880 2012-08-12 21:38:21

+0

谢谢何塞。自定义组件的想法似乎工作。在这里看到我自己的答案。将您的答案标记为正确的答案。 – user1139880 2012-08-12 22:04:39

+0

我发布了修复此错误的TextView的一些代码。希望能帮助到你。 http://stackoverflow.com/a/13386208/445348 – cottonBallPaws 2012-11-14 19:52:38

0

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

+0

向TextView添加的padding添加android:paddingBottom =“60dp”,但底线字体仍被截断。见http://imgur.com/du5xJ – user1139880 2012-08-12 21:33:04

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

结果文本视图呈现而不截断:

enter image description here

+0

这对你真的有用吗?对我来说,它的行为与底部填充相同 - 为textview增加了空间,但最后一行仍然被剪掉 – jab11 2013-10-25 16:43:36

1

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

虽然感觉对我来说,这个值应该被包含在onMeasure方法,你总是可以衡量你所需要的确切高度,然后做一个简单的检查:

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

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

希望它有帮助。

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

} 
9

littleFluffyKittys回答是好的,但如果linespacing通过XML设置

我计算了字体的原始高度与高度TextView的比较需要额外的高度并没有对某些设备计算一条线。 如果线条高度小于字体的高度,则会添加一次差异。

这适用到至少API 10 propably下(只是未测试任何低级)

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

} 
+1

这是这里最好的解决方案。 – 2014-02-05 19:40:17

+0

如果我需要以编程方式减少行间距(即setLineSpacing(float,float))适合您的解决方案,该怎么办? – ericn 2017-10-11 07:28:54

0

使用此,以减少在文本视图 **

机器人线间距:lineSpacingMultiplier = “0.8”

**