SpannableStringBuilder zum Erstellen eines Strings mit mehreren Schriftarten / Textgrößen usw. Beispiel?

78

Ich muss eine Zeichenfolge erstellen, die in einer Textansicht platziert ist und eine Zeichenfolge wie die folgende anzeigt:

Erster Teil nicht fett BOLD Rest nicht fett

Also möchte ich wissen, wie ich das machen könnte SpannableStringBuilder?

Ich könnte drei TextEdit verwenden, um dies zu erreichen, aber ich möchte die beste Lösung verwenden.

Code Droid
quelle

Antworten:

88
First Part Not Bold   BOLD  rest not bold

Sie können dies entweder wie von @Rajesh vorgeschlagen oder auf diese Weise tun.

String normalBefore= "First Part Not Bold ";
String normalBOLD=  "BOLD ";
String normalAfter= "rest not bold";
String finalString= normalBefore+normalBOLD+normalAfter;
Spannable sb = new SpannableString( finalString );
sb.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), finalString.indexOf(normalBOLD)+ normalBOLD.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //bold
sb.setSpan(new AbsoluteSizeSpan(intSize), finalString.indexOf(normalBOLD)+ normalBOLD.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);//resize size

um dies in TextView zu zeigen

textview.setText(sb,  TextView.BufferType.SPANNABLE);
Mohammed Azharuddin Shaikh
quelle
1
Wie kann ich auch die Schriftgröße für Fettdruck einstellen? Also spezifiziere ich beide, dass es fett ist und sage Schriftart 20?
Code Droid
7
Bitte aktualisieren Sie auch den Index auf (finalString.indexOf (normalBOLD), finalString.indexOf (normalBOLD) + normalBOLD.lenth ())
Code Droid
2
Neben dem, was CodeDroid gesagt hat, ist ein weiteres Problem, dass die indexOf-Methode ein wiederholtes Wort abfangen und Ihr endvor Ihrem startfür ein lassen kann IndexOutOfBoundsException. Es ist also besser, die Teilzeichenfolgen zu formatieren und dann zusammenzusetzen.
Noumenon
@hotveryspicy Ich vermute "finalString.indexOf (normalBOLD)" Dieser Teil ist - entgegen dem Aussehen - effizient, da String interniert ist. Ist es nicht so?
Paul Brewczynski
HINWEIS: android:textAllCaps="true"wird SpannableString
Jemand irgendwo
78

Die akzeptierte Antwort ist in Ordnung (und ich habe sie positiv bewertet), verwendet jedoch den SpannableStringBuilder nicht als angeforderten Übermittler. Da ich einen Fall hatte, in dem der Builder am sinnvollsten war, ist hier der Code dafür (mit dem Bonus, auch die Farbe des Textes zu ändern, wenn dies für andere hilfreich ist). Beachten Sie, dass Sie dem SpannableStringBuilder-Konstruktor auch die Anfangszeichenfolge bereitstellen können. Ich habe hier jedoch festgelegt, dass "Anhängen" verwendet wird, um zu verdeutlichen, dass Sie viel vor dem gewünschten "Fettdruck" anhängen und dann einfach den Start wie gezeigt aufzeichnen können. Ich würde vermuten, dass dies auch ein schnellerer Code ist als die akzeptierte Antwort.

SpannableStringBuilder longDescription = new SpannableStringBuilder();
longDescription.append("First Part Not Bold ");
int start = longDescription.length();
longDescription.append("BOLD");
longDescription.setSpan(new ForegroundColorSpan(0xFFCC5500), start, longDescription.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
longDescription.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), start, longDescription.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
longDescription.append(" rest not bold");
Josh
quelle
2
Wenn Sie die Startposition des fett gedruckten Teils des Textes vor dem Anhängen abrufen, müssen Sie sich keine Gedanken über doppelte Vorkommen des Wortes machen, das fett gedruckt werden soll.
Qw4z1
52

Wenn Sie Kotlin verwenden, können Sie mit der android-ktx- Bibliothek Folgendes tun

val s = SpannableStringBuilder()
        .append("First Part Not Bold ")
        .bold { append("BOLD") } 
        .append("Rest not bold")

Das boldist eine Erweiterungsfunktion an SpannableStringBuilder. In der Dokumentation finden Sie eine Liste der Vorgänge, die Sie verwenden können.

Ein anderes Beispiel:

val s = SpannableStringBuilder()
            .color(green, { append("Green text ") })
            .append("Normal text ")
            .scale(0.5, { append("Text at half size " })
            .backgroundColor(green, { append("Background green") })

Wo greenist eine aufgelöste RGB-Farbe.

Es ist sogar möglich, Bereiche zu verschachteln, sodass Sie ein eingebettetes DSL erhalten:

bold { underline { italic { append("Bold and underlined") } } }

Sie benötigen Folgendes in Ihrer App-Modulebene, build.gradledamit es funktioniert:

repositories {
    google()
}

dependencies {
    implementation "androidx.core:core-ktx:1.2.0"
}
David Rawson
quelle
2
Auf jeden Fall die beste Option, wenn Sie Kotlin verwenden können. Das DSL macht es zu einer viel, viel schöneren API.
Baptiste Candellier
1
Wie funktioniert es mit LiveData <String>? Ich kann nicht scheinen, diese Änderungen anzuwenden, obwohl alles kompiliert wird und in Ordnung aussieht?
gehorche dem
42

Ab API 21 enthält SpannableStringBuilder eine einfache Methode, um dies zu tun. Hier ist ein Lösungsbeispiel:

SpannableStringBuilder builder= new SpannableStringBuilder();
StyleSpan boldSpan = new StyleSpan(android.graphics.Typeface.BOLD);
builder.append("First Part Not Bold ")
              .append("BOLD ", boldSpan, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
              .append("rest not bold");

Da es eine gute Chance ist, dass Sie nicht nur API 21 unterstützen, können Sie den Code von dieser Methode duplizieren:

public SpannableStringBuilder append(CharSequence text, Object what, int flags) {
        int start = length();
        append(text);
        setSpan(what, start, length(), flags);
        return this;
}
Gober
quelle
7

Verwenden Sie HTML-Code in TextView mit der HtmlKlasse:

Spanned styledText = Html.fromHtml("First Part Not Bold <b>BOLD</b> rest not bold");
textView.setText(styledText);
Rajesh
quelle
19
Denken Sie daran, dass dies sehr langsam ist und wahrscheinlich dazu führt, dass Sie Frames überspringen, wenn dies während des Bildlaufs erfolgt.
Phil Kulak
6

Dieser Code sollte so eingestellt sein, dass alles, was im fettgedruckten HTML-Tag enthalten ist, fett gedruckt wird. Außerdem wird das Tag gelöscht, sodass nur der Inhalt angezeigt wird.

        SpannableStringBuilder sb = new SpannableStringBuilder("this is <b>bold</b> and this is <b>bold too</b>  and this is <b>bold too, again</b>.");

        Pattern p = Pattern.compile("<b>.*?</b>", Pattern.CASE_INSENSITIVE);            
        boolean stop = false;
        while (!stop)
        {
            Matcher m = p.matcher(sb.toString());
            if (m.find()) {
                sb.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
                sb.delete(m.end()-4, m.end());
                sb.delete(m.start(), m.start() + 3);
            }
            else
                stop = true;
        }

Dieser Code kann auch für andere HTML-Tags wie Superscript (sup-Tag) usw. angepasst werden.

        SpannableStringBuilder sb = new SpannableStringBuilder("text has <sup>superscript</sup> tag");

        Pattern p = Pattern.compile("<sup>.*?</sup>", Pattern.CASE_INSENSITIVE);            
        boolean stop = false;
        while (!stop)
        {
            Matcher m = p.matcher(sb.toString());
            if (m.find()) {
                sb.setSpan(new SuperscriptSpan(), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
                sb.delete(m.end()-6, m.end());
                sb.delete(m.start(), m.start() + 5);
            }
            else
                stop = true;
        }

Verwenden Sie zum Festlegen der Farbe einfach ForegroundColorSpan mit setSpan.

sb.setSpan(new ForegroundColorSpan(Color.rgb(255, 0, 0)), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);

Ich hoffe es hilft.

Live-Liebe
quelle
Perfekte Antwort, du hast meinen Tag gerettet! Ich habe das Muster durch val p = Pattern.compile ("<b> ([^ <] *) </ b>", Pattern.MULTILINE oder Pattern.DOTALL) ersetzt, weil Sie das Muster verwenden, wenn Sie nur das Start-Tag all haben Der Text ist fett gedruckt. Vielen Dank
AndroidRuntimeException
4

Ich weiß also, dass dies gelöst wurde, und selbst wie mit SpannableStringBuilder angefordert, aber für den Fall, dass Sie einen String dynamischer erstellen möchten, dachte ich, ich würde dies aufstellen.

// Stuff needed
TextView DataTextView = (TextView)rootView.findViewById(R.id.DataView);
String Fields[] = {...database column names as strings... "x","y"};

String DataString = new String();   

int start,stop;     // Start and Stop of formatting

// Final Result
SpannableStringBuilder coloredString = new SpannableStringBuilder(); 

SpannableString temp;       // Small segment of colored string
for (int i =0; i < Fields.length; i++)
{
    if (database_result.containsKey(Fields[i]))  // Be sure a field exists in the ContentValues
    {
            DataString = Fields[i]+": ";
        start = DataString.length();
        DataString = DataString+ +database_result.getAsInteger(Fields[i])+" ";
        stop= DataString.length();
        temp = new SpannableString(DataString);
        temp.setSpan(new ForegroundColorSpan(Color.WHITE),start, stop, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        coloredString.append(temp);
    }   
}
DataTextView.setText(coloredString);

database_result ist ein ContentValues-Typ, den ich aus dem zurückgegebenen Cursortyp der SQL-Abfrage erstellt habe. Das einzige Problem, das ich damit hatte, war zunächst, dass es nur ColorSpaning war, das erste Segment. Es scheint, dass Sie jedes Mal, wenn Sie eine (oder eine andere Art von Spanne) in einer Schleife verwenden möchten, eine neue ForegroundColorSpan deklarieren müssen.

Zeppie
quelle
3

Wir können auch SpannableStringBuilder mit TextAppearanceSpan verwenden , um dies zu erreichen. Befolgen Sie die folgenden Schritte, um dies zu implementieren.

  1. Erstellen Sie einen Stil in styles.xml.

<style name="BoldStyle">
   <!-- Can add other styling attributes -->
   <item name="android:textStyle">bold</item>
   ......
</style>

  1. Verwenden Sie den folgenden Code.
SpannableStringBuilder builder = neuer SpannableStringBuilder ("Erster Teil nicht fett fett fett Rest nicht fett");
builder.setSpan (neues TextAppearanceSpan (this, R.style.BoldStyle), 20, 24, 0);
((TextView) findViewById (R.id.tv7)). SetText (Builder);

Das ist es. Hoffe es wird jemandem helfen.

Mahendran Sakkarai
quelle
1

Warum sollten Sie SpannableStringBuilder verwenden, wenn Sie SpannableBuilder verwenden können? ( https://gist.github.com/qtyq/90f9b4894069a8b3676c )

SpannableString ss = SpannableBuilder.init("First Part Not Bold BOLD rest not bold")
                                     .makeBold("BOLD")
                                     .create()
Menge
quelle
4
weil spannablebuilder eine Spanne baut, während spannablestringbuilder für das Erstellen von Zeichenfolgen mit mehreren verschiedenen Spannen vorgesehen ist
Dabluck