2017-04-07 3 views
5

Ich möchte eine SpannedString auf eine Canvas zeichnen.Wie zeichne ich eine übergreifende Zeichenfolge mit Canvas.drawText in Android

enter image description here

SpannableString spannableString = new SpannableString("Hello World!"); 
ForegroundColorSpan foregroundSpan = new ForegroundColorSpan(Color.RED); 
BackgroundColorSpan backgroundSpan = new BackgroundColorSpan(Color.YELLOW); 
spannableString.setSpan(foregroundSpan, 1, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
spannableString.setSpan(backgroundSpan, 3, spannableString.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
textView.setText(spannableString); 

Das obige Beispiel wurde ein TextView gezogen Verwendung, die wiederum ein Layout verwendet, um Text mit Spannweiten zu ziehen. Ich weiß, dass using a Layout is the recommended way Text auf die Leinwand zeichnen. Allerdings mache ich mein eigenes Textlayout von Grund auf neu, also muss ich das selbst implementieren.

tun so etwas wie dieses nicht

canvas.drawText(spannableString, 0, spannableString.length(), 0, 0, mTextPaint); 

funktioniert, weil drawText nur den Text aus dem spannableString wird, keine der Spannweiten. Die Zeichnungsfarben werden separat von TextPaint behandelt.

Wie verwende ich canvas.drawText (oder drawTextRun), um die Span Informationen (speziell Vordergrund und Hintergrundfarbe hier) zu zeichnen?

Verwandte

Plan für eine Lösung

Ich wollte direkt eine Selbst Antwort zu tun, aber das erweist sich als zu mehr diff Schwieriger als ich dachte. Also werde ich zuerst posten und dann eine Antwort hinzufügen, wann immer ich es herausfinden kann. (Ich würde es begrüßen, natürlich jemand zuerst zu beantworten.)

Hier sind die Stücke, die ich bisher haben:

+0

so was ist das Problem mit 'Layout # draw' eigentlich? – pskink

+0

@pskink, der Standard 'Layout' verarbeitet nur horizontalen LTR- und RTL-Text. Ich mache ein vertikales Textlayout für [traditionelles mongolisches] (http://stackoverflow.com/q/29739720/3681880). Ich habe in der Vergangenheit verschiedene [Layout-Hacks] (http://stackoverflow.com/a/29739721/3681880) ausprobiert, aber selbst diese erlauben mir nicht, Emoji oder CJK-Zeichen zu drehen. Also fange ich bei Null an. [Ich habe die grundlegende Layout-Funktionalität abgeschlossen] (https://github.com/suragch/mongoll-library/blob/master/mongoll-library/src/main/java/net/studymongolian/mongollibrary/MongolLayout.java); Jetzt muss ich übergreifenden Text unterstützen. – Suragch

+0

ok, jetzt sehe ich, dass es kein "normales" 'Hallo Welt' ist, das du in deinem Bild – pskink

Antwort

3

Für die meisten Menschen auf diese Frage kommen, werden Sie wahrscheinlich eine StaticLayout verwenden sollten Ihre spannte Text zu zeichnen. Siehe this answer für Hilfe mit diesem.

Wenn Sie jedoch den überspannten Text tatsächlich selbst zeichnen müssen, dann müssen Sie loop through all the spanned ranges und zeichnen Sie jeweils separat. Sie müssen auch die Länge des Textes in jeder Spanne messen, damit Sie wissen, wo Sie mit dem Zeichnen der nächsten Spanne beginnen sollen.

Der folgende Code behandelt BackgroundColorSpan und ForegroundColorSpan.

// set up the spanned string 
SpannableString spannableString = new SpannableString("Hello World!"); 
ForegroundColorSpan foregroundSpan = new ForegroundColorSpan(Color.RED); 
BackgroundColorSpan backgroundSpan = new BackgroundColorSpan(Color.YELLOW); 
spannableString.setSpan(foregroundSpan, 1, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
spannableString.setSpan(backgroundSpan, 3, spannableString.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 

// draw each span one at a time 
int next; 
float xStart = 0; 
float xEnd; 
for (int i = 0; i < spannableString.length(); i = next) { 

    // find the next span transition 
    next = spannableString.nextSpanTransition(i, spannableString.length(), CharacterStyle.class); 

    // measure the length of the span 
    xEnd = xStart + mTextPaint.measureText(spannableString, i, next); 

    // draw the highlight (background color) first 
    BackgroundColorSpan[] bgSpans = spannableString.getSpans(i, next, BackgroundColorSpan.class); 
    if (bgSpans.length > 0) { 
     mHighlightPaint.setColor(bgSpans[0].getBackgroundColor()); 
     canvas.drawRect(xStart, mTextPaint.getFontMetrics().top, xEnd, mTextPaint.getFontMetrics().bottom, mHighlightPaint); 
    } 

    // draw the text with an optional foreground color 
    ForegroundColorSpan[] fgSpans = spannableString.getSpans(i, next, ForegroundColorSpan.class); 
    if (fgSpans.length > 0) { 
     int saveColor = mTextPaint.getColor(); 
     mTextPaint.setColor(fgSpans[0].getForegroundColor()); 
     canvas.drawText(spannableString, i, next, xStart, 0, mTextPaint); 
     mTextPaint.setColor(saveColor); 
    } else { 
     canvas.drawText(spannableString, i, next, xStart, 0, mTextPaint); 
    } 

    xStart = xEnd; 
} 

Die oberste Zeichenfolge im Bild unten wurde mit dem obigen Code gezeichnet. Die untere Zeichenkette wurde mit einer regulären TextView gezeichnet (die eine StaticLayout verwendet).

enter image description here

+0

Sie können die meisten anderen Spannen auf die gleiche Weise behandeln, wie die Vordergrundspanne gehandhabt wird update draw state Methode, die es automatisch macht (Ich füge das gerade als Kommentar hinzu, weil Ich kann mich nicht an die Einzelheiten erinnern. Wenn dies etwas ist, worüber du mehr Informationen haben möchtest, dann frage mich danach und ich werde diese Antwort aktualisieren.) – Suragch

Verwandte Themen