2012-08-12 22 views
7

Sto provando a ridurre l'interlinea in un TextView impostando un 'add' negativo a TextView.setLineSpacing(). Funziona bene, tranne che la linea di fondo viene troncata.Come ridurre l'interlinea di TextView

principale di layout

<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" /> 

Principale attività: (notare la

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

Questo si traduce in troncamento sul fondo della vista (notare la 'g' nella riga inferiore):

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

Sembra che il problema sia legato alla misurazione del layout non corretta. Se ho impostato il TextView a

android:layout_height="fill_parent" 

Non visualizzato correttamente:

Using 'fill_parent' does not truncate the bottom line

Qualsiasi idea di come risolvere il problema? Non mi dispiace avere brutte soluzioni alternative se aiuta. Ho anche accesso a FontForge e posso modificare il file di font, se necessario.

+0

accade con i caratteri incorporati? O altri caratteri personalizzati? Potrebbe essere che il font non stia riportando il valore di discesa corretto. – kcoppock

+1

sull'ultima riga si applica anche 'LineSpacing of -30f'. questo è il motivo per cui l'ultima riga non viene vista correttamente. così puoi 'settare il fondo padding' di 30 nel tuo caso ... @ kcoppock Non penso che ci sia qualcosa di sbagliato nei' valori di discesa' –

+0

@kcoppock, ho lo stesso problema con typeface = Typeface.SANS_SERIF; – user1139880

risposta

0

Se il padding non funziona, il margine dovrebbe fare il lavoro. Se il problema persiste, puoi sempre applicare il valore di spaziatura della linea al metodo onMeasure della vista. Dovrai creare uno custom component per quello ed estendere su Misura.

+0

Aggiunta di android: layout_margin = "20dp" o android: layout_marginBottom = "20dp" per TextView non ha aiutato. L'ultima riga è ancora troncata. Penso che il margine sia aggiunto dalla vista genitore, dopo che TextView ha determinato la misura desiderata. Proverò anche il suggerimento di componenti personalizzati. – user1139880

+0

Grazie Jose. L'idea del componente personalizzato sembra funzionare. Vedi la mia risposta qui. Contrassegnare la risposta come risposta corretta. – user1139880

+0

Ho pubblicato un codice per un TextView che corregge questo bug. Spero che sia d'aiuto. http://stackoverflow.com/a/13386208/445348 – cottonBallPaws

0

Basta aggiungere paddingBottom alla dichiarazione di vostro xml TextView, scegliere un valore che produce un buon risultato. E di conseguenza impostare i valori per altri paddings (superiore, let e destra). Questo dovrebbe risolvere il tuo problema

+0

Aggiunta di android: paddingBottom = "60dp" al padding aggiunto TextView ma il carattere di fondo è ancora troncato. Vedi http://imgur.com/du5xJ – user1139880

0

Questo è quello che ho fatto in base alla risposta di Jose qui e sembra funzionare. Non ho molta familiarità con l'intricato meccanismo del layout. Questo codice è sicuro? Qualche problema con esso?

Disposizione:

<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> 

Aggiunto TextView personalizzato che estende l'altezza verticale da N pixel:

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

Risultato vista testo di rendering senza troncamento in fondo:

enter image description here

+0

funziona davvero per te?per me agisce come il padding inferiore: aggiunge spazio a textview ma l'ultima linea è ancora ritagliata – jab11

1

Bello! Questo farà il lavoro ma non è mai una buona idea mettere i valori delle costanti ovunque ci siano variabili. È possibile utilizzare i valori lineSpacing per aggiungerli al metodo onMeasure in modo dinamico. Si noti che questi valori sono sempre disponibili tramite "getLineSpacingExtra()" e "getLineSpacingMultiplier()". O ancora più semplice è possibile ottenere il valore di entrambi riassunti: "getLineHeight()".

Anche se ci si sente per me che questo valore dovrebbe essere incluso nel metodo onMeasure, è sempre possibile misurare l'altezza esatta è necessario e poi fare un semplice controllo:

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

Un'ultima cosa, si don' t necessario passare il contesto lungo un attributo separato. Se dai un'occhiata ai tuoi costruttori, il contesto è già lì. Se hai bisogno del codice del tuo componente puoi semplicemente usare "getContext()".

Spero che aiuti.

6

mi sono imbattuto in questo stesso problema, ma quando stavo cercando di utilizzare un moltiplicatore distanza minore di 1.

ho creato una sottoclasse di TextView che fissa il troncamento dell'ultima riga in modo automatico e non richiede di impostare una spaziatura nota/fissa in basso.

Basta usare questa classe e la si può usare normalmente, non è necessario applicare ulteriori spaziature o correzioni.

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 risposta è buona, ma non ha funzionato su alcuni dispositivi se l'interlinea è stata impostata tramite XML

ho calcolare l'altezza supplementare necessario confrontando l'altezza originale del carattere con l'altezza del TextView calcola per una linea. Se l'altezza della linea è inferiore all'altezza del carattere, la diffrence viene aggiunta una volta.

Questo funziona fino ad almeno 10 API propably inferiore (solo non testato più in basso)

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

Questa è la soluzione migliore qui a mani basse. –

+0

Cosa devo fare se devo ridurre la spaziatura delle righe a livello di programmazione, cioè dove "setLineSpacing (float, float)" si adatta alla tua soluzione? – ericn

0

Usare questo per ridurre interlinea in modalità testo **

android: lineSpacingMultiplier = "0.8"

**