Ingrandire il singolo carattere in SpannableString avrà effetto sulla linea di spaziatura (solo in Marshmallow)

Ho il seguente metodo, che ingrandisce il primo carattere in TextView .

 private void makeFirstLetterBig(TextView textView, String title) { final SpannableString spannableString = new SpannableString(title); int position = 0; spannableString.setSpan(new RelativeSizeSpan(2.0f), position, position + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //textView.setText(spannableString.toString()); textView.setText(spannableString, BufferType.SPANNABLE); } 

Ecco il TextView utilizzato.

  • Autenticazione automatica per Android WiFi Direct
  • Custom ContentProvider - openInputStream (), openOutputStream ()
  • Come creare un hash di chiave di Facebook?
  • Leggere un file di text di grandi size in Textview
  • Come configurare Android Google Tag Manager v4 con Google Analytics (Universal Analytics)
  • Come aggiungere le caselle di controllo in modo dinamico in android
  •  <TextView android:id="@+id/title_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="16sp" android:textColor="?attr/newsTitleTextViewSelector" android:duplicateParentState="true" android:text="TextView" /> 

    Ecco il risultato prima di Marshmallow 6.

    immettere qui la descrizione dell'immagine

    Sembra abbastanza bene, come quando il contenuto del text si avvolge nella seconda row, il grande primo carattere non influisce sulla seconda row.

    Tuttavia, quando esegue la stessa applicazione in Marshmallow 6, ottengo il risultato seguente.

    immettere qui la descrizione dell'immagine

    Sembra che il grande personaggio "io" sta creando una grande imbottitura per l'integer contenuto del text. Ciò causa la seconda linea ( con Amazon ) ha una spaziatura enorme di linea con la prima linea.

    Posso sapere, come posso evitare questo problema in marshmallow 6? Voglio avere lo stesso risultato dei pre-marshmallow.

    p / s Ho inviato una relazione all'indirizzo https://code.google.com/p/android/issues/detail?id=191187 .

    Aggiornare

    Il 9 dicembre 2015, Google ha risolto questo problema e verrà rilasciato in Android 6.0.1 – https://code.google.com/p/android/issues/detail?id=191187

    3 Solutions collect form web for “Ingrandire il singolo carattere in SpannableString avrà effetto sulla linea di spaziatura (solo in Marshmallow)”

    TL; DR Il problema è causato da un bug nel metodo di generate di StaticLayout .

    Il bug è un po 'diverso da quello che ho pensato inizialmente, non riguarda tutte le righe ma solo quelle dopo il carattere ingrandito, come si può vedere dallo screenshot:

    immettere qui la descrizione dell'immagine

    In Marshmallow è stata aggiunta una cache FontMetrics per evitare la ricomposizione, come spiegato da un commento nel codice sorgente :

     // measurement has to be done before performing line breaking // but we don't want to recompute fontmetrics or span ranges the // second time, so we cache those and then use those stored values 

    Purtroppo il valore fm.descent disponibile nella cache viene eliminato se è inferiore al precedente valore memorizzato nella cache, come puoi vedere nello snippet :

     for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) { // retrieve end of span spanEnd = spanEndCache[spanEndCacheIndex++]; // retrieve cached metrics, order matches above fm.top = fmCache[fmCacheIndex * 4 + 0]; fm.bottom = fmCache[fmCacheIndex * 4 + 1]; fm.ascent = fmCache[fmCacheIndex * 4 + 2]; fm.descent = fmCache[fmCacheIndex * 4 + 3]; fmCacheIndex++; if (fm.top < fmTop) { fmTop = fm.top; } if (fm.ascent < fmAscent) { fmAscent = fm.ascent; } if (fm.descent > fmDescent) { fmDescent = fm.descent; } if (fm.bottom > fmBottom) { fmBottom = fm.bottom; } .... 

    Una volta che il valore raggiunge il massimo, non diminuirà mai e per questo each linea successiva ha uno spazio di linea maggiore.

    Non sono in grado di provarlo attualmente, ma questo sembra qualcosa che potresti lavorare con setLineSpacing : http://developer.android.com/reference/android/widget/TextView.html#setLineSpacing(float ,% 20float)

    Anche se c'è una risposta accettata, ecco la mia soluzione che funziona bene in Marshmallow. è solo un'applicazione ruvida per potervi migliorare.

    Conoscere le fonti di font predefinite del tuo paragrafo, sarebbe facile rilevare se si tratta di un ambito valido che cambia l'altezza della linea o è solo un bug, attuando chooseHeight() mehtod di LineHeightSpan che consente di accedere a each metrica di linea e l'intervallo.

    Per utilizzare, è sufficiente creare il tuo spannable e albind il markup vLineHeightCheckSpan al text integer o alla gamma del tuo desiderio.

    Risultato image

     public class vLineHeightCheckSpan implements LineHeightSpan { private int mAscent, mDescent, mTop, mBottom; private Spanned mSpanned; public vLineHeightCheckSpan(Spanned spanned, TextPaint defaultTextPaint) { Paint.FontMetricsInt fm = defaultTextPaint.getFontMetricsInt(); mAscent = fm.ascent; mDescent = fm.descent; mTop = fm.top; mBottom = fm.bottom; mSpanned = spanned; } @Override public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v, Paint.FontMetricsInt fm) { correctHeight(start, end, fm); } private void correctHeight(int start, int end, Paint.FontMetricsInt fm) { // check whether the line bound is different than default if(fm.top < mTop || fm.bottom > mBottom) { // get all spans which might affect the line height MetricAffectingSpan[] spans = mSpanned.getSpans(start, end, MetricAffectingSpan.class); // if there is none, set the line metrics to default if(spans.length == 0) { fm.top = mTop; fm.ascent = mAscent; fm.descent = mDescent; fm.bottom = mBottom; } } } } 

    utilizzo:

      // default layout textPaint TextPaint defaultTextPaint = new TextPaint(textPaint); // spannable Spannable styledText = new SpannableString(mText); final BackgroundColorSpan backgroundColor = new BackgroundColorSpan(Color.YELLOW); final ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.RED); final LeadingMarginSpan leadingMarginSpan = new LeadingMarginSpan.Standard(leading); final AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(leadSize); styledText.setSpan(foregroundColorSpan, highLightStart, highLightEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); styledText.setSpan(backgroundColor, highLightStart, highLightEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); styledText.setSpan(leadingMarginSpan, 0, mText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); styledText.setSpan(absoluteSizeSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // add the line height check span if (android.os.Build.VERSION.SDK_INT == 23) { final vLineHeightCheckSpan checkHeightSpan = new vLineHeightCheckSpan(styledText, defaultTextPaint); styledText.setSpan(checkHeightSpan, 0, mText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } mLayout = new StaticLayout(styledText, defaultTextPaint, (int) initialRect.width(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0, false); 
    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.