Wie füge ich ein Bild in einen TextView-Text ein?

82

Ich habe mich bei Google umgesehen und bin auf diese Website gestoßen, auf der ich eine ähnliche Frage gefunden habe, wie man ein Bild in einen TextViewText einfügt , zum Beispiel "Hallo, mein Name ist [Bild]" . Die Antwort lautete wie folgt :

ImageSpan is = new ImageSpan(context, resId);
text.setSpan(is, index, index + strLength, 0);

Ich würde gerne in diesem Code wissen,

  1. Was soll ich im Kontext tippen oder tun?
  2. Soll ich etwas tun, um etwas zu text.setSpan()importieren oder zu referenzieren oder es als Text zu belassen?

Wenn jemand dies für mich aufschlüsseln kann, wäre das sehr dankbar.

Cranosaurier
quelle

Antworten:

197

Versuche dies ..

    txtview.setCompoundDrawablesWithIntrinsicBounds(
                    R.drawable.image, 0, 0, 0);

Siehe auch dies .. http://developer.android.com/reference/android/widget/TextView.html

Versuchen Sie dies in einer XML-Datei

    <TextView
        android:id="@+id/txtStatus"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:drawableLeft="@drawable/image"
        android:drawablePadding="5dp"
        android:maxLines="1"
        android:text="@string/name"/>
Umesh Lakhani
quelle
Ich habe eine Fehlermeldung "Kann keinen statischen Verweis auf die nicht statische Methode setCompoundDrawablesWithIntrinsicBounds (int, int, int, int) vom Typ TextView erstellen"
Cranosaur
Danke Umesh, die XML-Methode hat bei mir funktioniert. Ich verwende das XML-Layout für meine TextViews, daher weiß ich nicht, ob dies einen Unterschied macht, und vielleicht hat es deshalb in Java nicht funktioniert.
Cranosaur
1
@Umesh Lakhani: Wie ist es möglich, mit diesem Ansatz mehrere Drawables in Text einzufügen?
Behnam
In XML wird ein Bild von links gezeichnet, nicht in der Mitte.
CoolMind
HI @Umesh. Wie man einen gewissen Rand einstellt. setCompoundDrawablePaddingmacht nichts
Prabs
73

com / xyz / customandroid / TextViewWithImages .java :

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.content.Context;
import android.text.Spannable;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

public class TextViewWithImages extends TextView {

    public TextViewWithImages(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    public TextViewWithImages(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public TextViewWithImages(Context context) {
        super(context);
    }
    @Override
    public void setText(CharSequence text, BufferType type) {
        Spannable s = getTextWithImages(getContext(), text);
        super.setText(s, BufferType.SPANNABLE);
    }

    private static final Spannable.Factory spannableFactory = Spannable.Factory.getInstance();

    private static boolean addImages(Context context, Spannable spannable) {
        Pattern refImg = Pattern.compile("\\Q[img src=\\E([a-zA-Z0-9_]+?)\\Q/]\\E");
        boolean hasChanges = false;

        Matcher matcher = refImg.matcher(spannable);
    while (matcher.find()) {
        boolean set = true;
        for (ImageSpan span : spannable.getSpans(matcher.start(), matcher.end(), ImageSpan.class)) {
            if (spannable.getSpanStart(span) >= matcher.start()
             && spannable.getSpanEnd(span) <= matcher.end()
               ) {
                spannable.removeSpan(span);
            } else {
                set = false;
                break;
            }
        }
        String resname = spannable.subSequence(matcher.start(1), matcher.end(1)).toString().trim();
        int id = context.getResources().getIdentifier(resname, "drawable", context.getPackageName());
        if (set) {
            hasChanges = true;
            spannable.setSpan(  new ImageSpan(context, id),
                                matcher.start(),
                                matcher.end(),
                                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                             );
        }
    }

        return hasChanges;
    }
    private static Spannable getTextWithImages(Context context, CharSequence text) {
        Spannable spannable = spannableFactory.newSpannable(text);
        addImages(context, spannable);
        return spannable;
    }
}

Verwenden:

in res / layout / mylayout.xml :

            <com.xyz.customandroid.TextViewWithImages
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#FFFFFF00"
                android:text="@string/can_try_again"
                android:textSize="12dip"
                style=...
                />

Beachten Sie, dass Sie den Paketnamen oben ändern müssen , wenn Sie TextViewWithImages.java an einem anderen Ort als com / xyz / customandroid / platzierencom.xyz.customandroid .

in res / values ​​/ strings.xml :

<string name="can_try_again">Press [img src=ok16/] to accept or [img src=retry16/] to retry</string>

Dabei sind ok16.png und retry16.png Symbole im Ordner res / drawable /

18446744073709551615
quelle
Wenn ich es benutze textView.setText(R.string.can_try_again);, werden die Bilder nicht angezeigt, sondern nur der Klartext Press [img src=ok16/] to accept or [img src=retry16/] to retry. Irgendeine Hilfe? Dies liegt daran, dass ich die Bilder dynamisch laden und in der Textansicht festlegen möchte.
Anas Azeem
@AnasAzeem können Sie ok16 und retry16 "normal" über ImageView anzeigen? Haben Sie TextViewWithImages anstelle von TextView angegeben?
18446744073709551615
1
Vergessen Sie nicht, <com.xyz.customandroid.TextViewWithImages durch <YourPackageName.TextViewWithImages zu ändern, da sonst ein Fehler beim Aufblasen und eine NoClassFound-Ausnahme
aufgetreten ist
1
Es funktioniert, aber ich kann die Höhe des Bildes nicht einstellen und auch das Bild nicht in die Mitte des Textes bringen
Rajesh Koshti
1
Es ist eine großartige Klasse, bis Sie es in einem Release-Build verpacken. Es stürzt ab und ich konnte immer noch nicht herausfinden warum. Sogar diese Klasse in der Proguard-Führung markiert. Immer noch kein Glück. Oder vielleicht sind die Bilder, die ich verwendet habe, Vektoren, weshalb es vielleicht abgestürzt ist. Ich weiß es nicht.
Uday
18

Ich habe viele verschiedene Lösungen ausprobiert und dies war für mich das Beste:

SpannableStringBuilder ssb = new SpannableStringBuilder(" Hello world!");
ssb.setSpan(new ImageSpan(context, R.drawable.image), 0, 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
tv_text.setText(ssb, TextView.BufferType.SPANNABLE);

Dieser Code benötigt ein Minimum an Speicher.

Pavel Kataykin
quelle
1
In diesem Fall Bild hinzugefügt, aber mit der Grundlinie des Textes ausrichten Ich möchte mit dem oberen
Rand
2
es funktioniert, aber wie können wir die Größe des Bildsymbols entsprechend der Textgröße ändern
sunil kushwah
11

Diese Antwort basiert auf dieser ausgezeichneten Antwort von 18446744073709551615 . Ihre Lösung ist zwar hilfreich, passt das Bildsymbol jedoch nicht an den umgebenden Text an. Außerdem wird die Symbolfarbe nicht auf die des umgebenden Textes eingestellt.

Die folgende Lösung verwendet ein weißes, quadratisches Symbol und passt es an die Größe und Farbe des umgebenden Textes an.

public class TextViewWithImages extends TextView {

    private static final String DRAWABLE = "drawable";
    /**
     * Regex pattern that looks for embedded images of the format: [img src=imageName/]
     */
    public static final String PATTERN = "\\Q[img src=\\E([a-zA-Z0-9_]+?)\\Q/]\\E";

    public TextViewWithImages(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public TextViewWithImages(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TextViewWithImages(Context context) {
        super(context);
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        final Spannable spannable = getTextWithImages(getContext(), text, getLineHeight(), getCurrentTextColor());
        super.setText(spannable, BufferType.SPANNABLE);
    }

    private static Spannable getTextWithImages(Context context, CharSequence text, int lineHeight, int colour) {
        final Spannable spannable = Spannable.Factory.getInstance().newSpannable(text);
        addImages(context, spannable, lineHeight, colour);
        return spannable;
    }

    private static boolean addImages(Context context, Spannable spannable, int lineHeight, int colour) {
        final Pattern refImg = Pattern.compile(PATTERN);
        boolean hasChanges = false;

        final Matcher matcher = refImg.matcher(spannable);
        while (matcher.find()) {
            boolean set = true;
            for (ImageSpan span : spannable.getSpans(matcher.start(), matcher.end(), ImageSpan.class)) {
                if (spannable.getSpanStart(span) >= matcher.start()
                        && spannable.getSpanEnd(span) <= matcher.end()) {
                    spannable.removeSpan(span);
                } else {
                    set = false;
                    break;
                }
            }
            final String resName = spannable.subSequence(matcher.start(1), matcher.end(1)).toString().trim();
            final int id = context.getResources().getIdentifier(resName, DRAWABLE, context.getPackageName());
            if (set) {
                hasChanges = true;
                spannable.setSpan(makeImageSpan(context, id, lineHeight, colour),
                        matcher.start(),
                        matcher.end(),
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                );
            }
        }
        return hasChanges;
    }

    /**
     * Create an ImageSpan for the given icon drawable. This also sets the image size and colour.
     * Works best with a white, square icon because of the colouring and resizing.
     *
     * @param context       The Android Context.
     * @param drawableResId A drawable resource Id.
     * @param size          The desired size (i.e. width and height) of the image icon in pixels.
     *                      Use the lineHeight of the TextView to make the image inline with the
     *                      surrounding text.
     * @param colour        The colour (careful: NOT a resource Id) to apply to the image.
     * @return An ImageSpan, aligned with the bottom of the text.
     */
    private static ImageSpan makeImageSpan(Context context, int drawableResId, int size, int colour) {
        final Drawable drawable = context.getResources().getDrawable(drawableResId);
        drawable.mutate();
        drawable.setColorFilter(colour, PorterDuff.Mode.MULTIPLY);
        drawable.setBounds(0, 0, size, size);
        return new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM);
    }

}

Wie benutzt man:

Betten Sie einfach Verweise auf die gewünschten Symbole in den Text ein. Es spielt keine Rolle, ob der Text programmgesteuert textView.setText(R.string.string_resource);oder in XML festgelegt wird.

Fügen Sie die folgende Zeichenfolge in den Text ein, um ein zeichnbares Symbol mit dem Namen example.png einzubetten : [img src=example/].

Eine Zeichenfolgenressource könnte beispielsweise folgendermaßen aussehen:

<string name="string_resource">This [img src=example/] is an icon.</string>
Stellen Sie Monica wieder her
quelle
3
Dies ist eine gute Lösung. Ich würde nur eine Verbesserung vorschlagen: füge drawable.mutate () vor drawable.setColorFilter hinzu; Wenn Sie dies nicht tun, haben Sie das Zeichen mit einer anderen Farbe in anderen Teilen Ihrer App.
Moondroid
@moondroid Danke für den Vorschlag, ich habe die Antwort entsprechend bearbeitet.
Stellen Sie Monica
Eigentlich hatte ich ein Problem, weil mein Zeichenelement nicht quadratisch ist und diese Lösung die Zeichenbreite immer mit der Zeichenhöhe gleich macht. Dadurch wird die Größe meines Zeichenobjekts überproportional geändert
HendraWD
1

Dies basiert teilweise auf dieser früheren Antwort von @A Boschman . In dieser Lösung stellte ich fest, dass die Eingabegröße des Bildes die Fähigkeit makeImageSpan(), das Bild richtig zentriert auszurichten, stark beeinflusste . Außerdem stellte ich fest, dass die Lösung den Textabstand beeinflusste, indem unnötige Zeilenabstände erzeugt wurden.

Ich fand, dass BaseImageSpan (aus der Fresco-Bibliothek von Facebook) die Arbeit besonders gut macht:

 /**
 * Create an ImageSpan for the given icon drawable. This also sets the image size. Works best
 * with a square icon because of the sizing
 *
 * @param context       The Android Context.
 * @param drawableResId A drawable resource Id.
 * @param size          The desired size (i.e. width and height) of the image icon in pixels.
 *                      Use the lineHeight of the TextView to make the image inline with the
 *                      surrounding text.
 * @return An ImageSpan, aligned with the bottom of the text.
 */
private static BetterImageSpan makeImageSpan(Context context, int drawableResId, int size) {
    final Drawable drawable = context.getResources().getDrawable(drawableResId);
    drawable.mutate();
    drawable.setBounds(0, 0, size, size);
    return new BetterImageSpan(drawable, BetterImageSpan.ALIGN_CENTER);
}

Geben Sie dann Ihre betterImageSpan-Instanz spannable.setSpan()wie gewohnt an

kip2
quelle