¿Cómo agregar una imagen en un texto TextView?

83

Busqué en Google y encontré este sitio donde encontré una pregunta similar a la mía en la que cómo incluir una imagen en un TextViewtexto, por ejemplo, "hola, mi nombre es [imagen]" , y la respuesta fue esta:

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

Me gustaría saber en este código,

  1. ¿Qué se supone que debo escribir o hacer en el contexto?
  2. ¿Se supone que debo hacer algo para text.setSpan()importar o hacer referencia o dejarlo como texto?

Si alguien puede desglosar esto por mí, sería muy apreciado.

Cranosaurio
fuente

Respuestas:

200

Prueba esto ..

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

También vea esto .. http://developer.android.com/reference/android/widget/TextView.html

Prueba esto en un archivo xml

    <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
fuente
Recibí un error "No se puede hacer una referencia estática al método no estático setCompoundDrawablesWithIntrinsicBounds (int, int, int, int) del tipo TextView"
Cranosaur
Gracias Umesh, el método xml funcionó para mí. Uso el diseño xml para mis TextViews, así que no sé si eso hace una diferencia y tal vez por eso no funcionaba en Java.
Cranosaurio
1
@Umesh Lakhani: ¿Cómo es posible poner varios elementos de diseño en el texto con este enfoque?
Behnam
En XML, una imagen se dibuja desde la izquierda, no en el centro.
CoolMind
Hola @Umesh. Cómo ponerle un margen. setCompoundDrawablePaddingno está haciendo nada
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;
    }
}

Utilizar:

en 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=...
                />

Tenga en cuenta que si coloca TextViewWithImages.java en una ubicación que no sea com / xyz / customandroid / , también debe cambiar el nombre del paquete, com.xyz.customandroidarriba.

en res / values ​​/ strings.xml :

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

donde ok16.png y retry16.png son iconos en la carpeta res / drawable /

18446744073709551615
fuente
Cuando lo uso textView.setText(R.string.can_try_again);no muestra las imágenes, simplemente muestra el texto sin formato Press [img src=ok16/] to accept or [img src=retry16/] to retry. ¿Alguna ayuda? Esto se debe a que quiero cargar dinámicamente las imágenes y configurarlas en textView.
Anas Azeem
@AnasAzeem, ¿puedes mostrar ok16 y reintentar16 "normalmente", a través de ImageView? ¿Especificó TextViewWithImages en lugar de TextView?
18446744073709551615
1
no olvide cambiar <com.xyz.customandroid.TextViewWithImages con <YourPackageName.TextViewWithImages; de lo contrario, obtendrá un error al inflar y la excepción NoClassFound
AndroidGeek
1
su trabajo, pero no puedo establecer anchura altura de la imagen y también no obtener la imagen en el centro del texto
Rajesh Koshti
1
Es una gran clase hasta que la empaqueta en una versión de lanzamiento. Se bloquea y todavía no he podido averiguar por qué. Incluso marcó esta clase en el -keep in proguard. Sigo sin suerte. O tal vez las imágenes que utilicé son vectoriales, por eso tal vez se bloqueó. No lo sé.
Udayaditya Barua
18

Probé muchas soluciones diferentes y esta para mí fue la mejor:

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);

Este código usa un mínimo de memoria.

Pavel Kataykin
fuente
2
en ese caso, se agregó la imagen pero se alineó con la línea de base del texto que quiero alinear con la parte superior del texto, ¿pueden ayudarme?
humayoon siddique
2
funciona pero ¿cómo podemos cambiar el tamaño de la imagen del icono de acuerdo con el tamaño del texto
Kushwah Sunil
12

Esta respuesta se basa en esta excelente respuesta de 18446744073709551615 . Su solución, aunque útil, no ajusta el tamaño del icono de la imagen con el texto circundante. Tampoco establece el color del icono en el del texto circundante.

La siguiente solución toma un ícono cuadrado blanco y lo ajusta al tamaño y color del texto circundante.

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);
    }

}

Cómo utilizar:

Simplemente inserte referencias a los iconos deseados en el texto. No importa si el texto está configurado mediante programación textView.setText(R.string.string_resource);o si está configurado en xml.

Para incrustar un icono llamado dibujable example.png, incluye la siguiente cadena en el texto: [img src=example/].

Por ejemplo, un recurso de cadena podría verse así:

<string name="string_resource">This [img src=example/] is an icon.</string>
Reincorporar a Monica
fuente
3
Esta es una buena solución. Sugeriría solo una mejora: agregue drawable.mutate () antes de drawable.setColorFilter; si no lo hace, tendrá el dibujable con un color diferente en otras partes de su aplicación.
Moondroid
@moondroid Gracias por la sugerencia, edité la respuesta en consecuencia.
Reincorporar a Monica
En realidad, tuve un problema, porque mi elemento de dibujo no es cuadrado, y esta solución siempre hará que el ancho del elemento de
dibujo
1

Esto se basa en parte en esta respuesta anterior de @A Boschman . En esa solución, descubrí que el tamaño de entrada de la imagen afectó en gran medida la capacidad de makeImageSpan()alinear correctamente el centro de la imagen. Además, descubrí que la solución afectaba el espaciado del texto al crear un espaciado de línea innecesario.

Encontré BaseImageSpan (de la biblioteca Fresco de Facebook) para hacer el trabajo particularmente bien:

 /**
 * 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);
}

Luego proporcione su instancia betterImageSpan spannable.setSpan()como de costumbre

kip2
fuente
0

Esto podría ayudarte

  SpannableStringBuilder ssBuilder;

        ssBuilder = new SpannableStringBuilder(" ");
        // working code ImageSpan image = new ImageSpan(textView.getContext(), R.drawable.image);
        Drawable image = ContextCompat.getDrawable(textView.getContext(), R.drawable.image);
        float scale = textView.getContext().getResources().getDisplayMetrics().density;
        int width = (int) (12 * scale + 0.5f);
        int height = (int) (18 * scale + 0.5f);
        image.setBounds(0, 0, width, height);
        ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BASELINE);
        ssBuilder.setSpan(
                imageSpan, // Span to add
                0, // Start of the span (inclusive)
                1, // End of the span (exclusive)
                Spanned.SPAN_INCLUSIVE_EXCLUSIVE);// Do not extend the span when text add later

        ssBuilder.append(" " + text);
        ssBuilder = new SpannableStringBuilder(text);
        textView.setText(ssBuilder);
Himanshu saini
fuente