2017-04-07 5 views
5

Je veux dessiner un SpannedString à un Canvas.Comment dessiner une chaîne avec fractionnés Canvas.drawText dans 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); 

L'exemple ci-dessus a été dessiné à l'aide d'un TextView, qui à son tour utilise un Layout pour dessiner le texte avec des portées. Je sais que using a Layout is the recommended way pour dessiner du texte sur la toile. Cependant, je suis en train de créer ma propre mise en page de texte, donc j'ai besoin de la mettre en œuvre moi-même.

Faire quelque chose comme cela ne fonctionne pas

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

parce que drawText obtient le texte de la spannableString, aucun des travées. Les couleurs de dessin sont gérées séparément par TextPaint.

Comment est-ce que j'utilise canvas.drawText (ou drawTextRun) pour dessiner l'information d'envergure (spécifiquement la couleur de premier plan et d'arrière-plan ici)?

connexes

Plan pour une solution

J'allais faire directement une auto réponse mais cela se avère être plus diff icult que je pensais. Donc, je vais poster d'abord, puis ajouter une réponse chaque fois que je peux le comprendre. (Je bien sûr la bienvenue à quiconque de répondre à la première.)

Voici les pièces que j'ai jusqu'à présent:

+0

alors quel est le problème avec la mise en page 'draw' en fait? – pskink

+0

@pskink, la mise en page standard ne traite que les textes horizontaux LTR et RTL. Je suis en train de faire une mise en page verticale de texte pour [mongol traditionnel] (http://stackoverflow.com/q/29739720/3681880). J'ai essayé plusieurs [Layout hacks] (http://stackoverflow.com/a/29739721/3681880) dans le passé, mais même ceux-ci ne me permettent pas de faire tourner les emoji ou les caractères CJK. Donc je pars de zéro. [J'ai terminé la fonctionnalité de mise en page de base] (https://github.com/suragch/mongol-library/blob/master/mongol-library/src/main/java/net/studymongolian/mongollibrary/MongolLayout.java); maintenant je dois soutenir le texte étendu. – Suragch

+0

ok, maintenant je vois que ce n'est pas un "normal" 'Hello World' que vous avez présenté dans votre image – pskink

Répondre

3

Pour la plupart des gens qui viennent à cette question, vous devriez probablement utiliser un StaticLayout pour dessiner votre texte étalonnés. Voir this answer pour de l'aide avec ça.

Cependant, si vous avez réellement besoin de dessiner vous-même le texte, alors vous devrez loop through all the spanned ranges et dessiner chacun séparément. Vous devez également mesurer la longueur du texte dans chaque intervalle afin de savoir où commencer à dessiner l'intervalle suivant. Le code ci-dessous traite BackgroundColorSpan et 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; 
} 

La chaîne supérieure de l'image ci-dessous a été dessinée avec le code ci-dessus. La chaîne du bas a été dessinée avec un TextView (qui utilise un StaticLayout).

enter image description here

+0

Vous pouvez gérer la plupart des autres travées de la même manière que l'extension de premier plan. mettre à jour la méthode d'état de tirage qui le fera automatiquement (j'ajoute juste ceci comme commentaire pour l'instant parce que Je ne me souviens plus des détails. Si c'est quelque chose que vous souhaitez plus d'infos sur alors demandez-moi à ce sujet et je vais mettre à jour cette réponse.) – Suragch