Pregunta ¿Es posible mostrar imágenes en línea desde html en un Android TextView?


Dado el siguiente HTML:

<p>This is text and this is an image <img src="http://www.example.com/image.jpg" />.</p>

¿Es posible hacer que la imagen se renderice? Al usar este fragmento: mContentText.setText(Html.fromHtml(text));, Obtengo una caja cian con bordes negros, lo que me lleva a creer que un TextView tiene una idea de lo que es una etiqueta img.


75
2018-05-19 12:30


origen


Respuestas:


Si miras el documentación para Html.fromHtml(text) Verás que dice:

Alguna <img> las etiquetas en el HTML se mostrarán como una imagen de reemplazo genérica que su programa puede luego pasar y reemplazar con imágenes reales.

Si no desea hacer este reemplazo usted mismo puede usar el otro Html.fromHtml() método que toma una Html.TagHandler y un Html.ImageGetter como argumentos, así como el texto para analizar.

En tu caso podrías analizar null En cuanto a Html.TagHandler pero necesitarías implementar tu propio Html.ImageGetter ya que no hay una implementación predeterminada.

Sin embargo, el problema que vas a tener es que Html.ImageGetter necesita ejecutarse de forma sincronizada y, si está descargando imágenes de la web, probablemente desee hacerlo de forma asincrónica. Si puede agregar cualquier imagen que quiera mostrar como recursos en su aplicación, su ImageGetter la implementación se vuelve mucho más simple. Podrías salir con algo como esto:

private class ImageGetter implements Html.ImageGetter {

    public Drawable getDrawable(String source) {
        int id;

        if (source.equals("stack.jpg")) {
            id = R.drawable.stack;
        }
        else if (source.equals("overflow.jpg")) {
            id = R.drawable.overflow;
        }
        else {
            return null;
        }

        Drawable d = getResources().getDrawable(id);
        d.setBounds(0,0,d.getIntrinsicWidth(),d.getIntrinsicHeight());
        return d;
    }
};

Sin embargo, es probable que desee averiguar algo más inteligente para mapear cadenas fuente a ID de recursos.


114
2018-05-19 13:35



Lo he implementado en mi aplicación, tomado como referencia del pskink.Muchas gracias

package com.example.htmltagimg;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LevelListDrawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Html;
import android.text.Html.ImageGetter;
import android.text.Spanned;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends Activity implements ImageGetter {
private final static String TAG = "TestImageGetter";
private TextView mTv;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    String source = "this is a test of <b>ImageGetter</b> it contains " +
            "two images: <br/>" +
            "<img src=\"http://developer.android.com/assets/images/dac_logo.png\"><br/>and<br/>" +
            "<img src=\"http://www.hdwallpapersimages.com/wp-content/uploads/2014/01/Winter-Tiger-Wild-Cat-Images.jpg\">";
    String imgs="<p><img alt=\"\" src=\"http://images.visitcanberra.com.au/images/canberra_hero_image.jpg\" style=\"height:50px; width:100px\" />Test Article, Test Article, Test Article, Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,v</p>";
    String src="<p><img alt=\"\" src=\"http://stylonica.com/wp-content/uploads/2014/02/Beauty-of-nature-random-4884759-1280-800.jpg\" />Test Attractions Test Attractions Test Attractions Test Attractions</p>";
    String img="<p><img alt=\"\" src=\"/site_media/photos/gallery/75b3fb14-3be6-4d14-88fd-1b9d979e716f.jpg\" style=\"height:508px; width:640px\" />Test Article, Test Article, Test Article, Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,Test Article,v</p>";
    Spanned spanned = Html.fromHtml(imgs, this, null);
    mTv = (TextView) findViewById(R.id.text);
    mTv.setText(spanned);
}

@Override
public Drawable getDrawable(String source) {
    LevelListDrawable d = new LevelListDrawable();
    Drawable empty = getResources().getDrawable(R.drawable.ic_launcher);
    d.addLevel(0, 0, empty);
    d.setBounds(0, 0, empty.getIntrinsicWidth(), empty.getIntrinsicHeight());

    new LoadImage().execute(source, d);

    return d;
}

class LoadImage extends AsyncTask<Object, Void, Bitmap> {

    private LevelListDrawable mDrawable;

    @Override
    protected Bitmap doInBackground(Object... params) {
        String source = (String) params[0];
        mDrawable = (LevelListDrawable) params[1];
        Log.d(TAG, "doInBackground " + source);
        try {
            InputStream is = new URL(source).openStream();
            return BitmapFactory.decodeStream(is);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        Log.d(TAG, "onPostExecute drawable " + mDrawable);
        Log.d(TAG, "onPostExecute bitmap " + bitmap);
        if (bitmap != null) {
            BitmapDrawable d = new BitmapDrawable(bitmap);
            mDrawable.addLevel(1, 1, d);
            mDrawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
            mDrawable.setLevel(1);
            // i don't know yet a better way to refresh TextView
            // mTv.invalidate() doesn't work as expected
            CharSequence t = mTv.getText();
            mTv.setText(t);
        }
    }
}
}

Según el comentario de @rpgmaker a continuación agregué esta respuesta

sí puedes hacer uso ResolveInfo clase

compruebe que su archivo sea compatible con las aplicaciones ya instaladas o no

usando el siguiente código:

private boolean isSupportedFile(File file) throws PackageManager.NameNotFoundException {
    PackageManager pm = mContext.getPackageManager();
    java.io.File mFile = new java.io.File(file.getFileName());
    Uri data = Uri.fromFile(mFile);
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(data, file.getMimeType());
    List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);

    if (resolveInfos != null && resolveInfos.size() > 0) {
        Drawable icon = mContext.getPackageManager().getApplicationIcon(resolveInfos.get(0).activityInfo.packageName);
        Glide.with(mContext).load("").placeholder(icon).into(binding.fileAvatar);
        return true;
    } else {
        Glide.with(mContext).load("").placeholder(R.drawable.avatar_defaultworkspace).into(binding.fileAvatar);
        return false;
    }
}

12
2018-02-11 18:25



Esto es lo que uso, que no necesita forzar los nombres de tus recursos y buscar los recursos dibujables primero en tus recursos de aplicaciones y luego en los recursos android en existencia si no se encuentra nada, lo que te permite usar íconos predeterminados y demás.

private class ImageGetter implements Html.ImageGetter {

     public Drawable getDrawable(String source) {
        int id;

        id = getResources().getIdentifier(source, "drawable", getPackageName());

        if (id == 0) {
            // the drawable resource wasn't found in our package, maybe it is a stock android drawable?
            id = getResources().getIdentifier(source, "drawable", "android");
        }

        if (id == 0) {
            // prevent a crash if the resource still can't be found
            return null;    
        }
        else {
            Drawable d = getResources().getDrawable(id);
            d.setBounds(0,0,d.getIntrinsicWidth(),d.getIntrinsicHeight());
            return d;
        }
     }

 }

Que se puede usar como tal (ejemplo):

String myHtml = "This will display an image to the right <img src='ic_menu_more' />";
myTextview.setText(Html.fromHtml(myHtml, new ImageGetter(), null);

9
2018-03-10 11:25



Enfrenté el mismo problema y encontré una solución bastante limpia: después de Html.fromHtml () puede ejecutar una AsyncTask que itera sobre todas las etiquetas, busca las imágenes y luego las muestra.

Aquí puede encontrar un código que puede usar (pero necesita cierta personalización): https://gist.github.com/1190397


5
2017-09-03 02:03



Utilicé la respuesta de Dave Webb pero la simplifiqué un poco. Mientras los ID de recursos permanezcan iguales durante el tiempo de ejecución en su caso de uso, no es realmente necesario escribir su propia clase implementando Html.ImageGetter y perder el tiempo con las cadenas fuente.

Lo que hice fue usar el ID del recurso como una cadena fuente:

final String img = String.format("<img src=\"%s\"/>", R.drawable.your_image);
final String html = String.format("Image: %s", img);

y usarlo directamente:

Html.fromHtml(html, new Html.ImageGetter() {
  @Override
  public Drawable getDrawable(final String source) {
    Drawable d = null;
    try {
      d = getResources().getDrawable(Integer.parseInt(source));
      d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
    } catch (Resources.NotFoundException e) {
      Log.e("log_tag", "Image not found. Check the ID.", e);
    } catch (NumberFormatException e) {
      Log.e("log_tag", "Source string not a valid resource ID.", e);
    }

    return d;
  }
}, null);

3
2018-01-17 14:52



También puede escribir su propio analizador para extraer la URL de todas las imágenes y luego crear dinámicamente nuevas imágenes y pasar las URL.


1
2018-06-25 04:41



Además, si desea realizar el reemplazo usted mismo, el personaje que debe buscar es [].

Pero si usa Eclipse, se volverá loco cuando escriba esa letra en una declaración [replace] indicándole que entra en conflicto con Cp1252; este es un error de Eclipse. Para solucionarlo, ve a

Ventana -> Preferencias -> General -> Espacio de trabajo -> Codificación de archivo de texto,

y seleccione [UTF-8]


1
2018-06-25 04:20



En caso de que alguien piense que los recursos deben ser declarativos y usar Spannable para múltiples idiomas es un desastre, hice algunas vistas personalizadas

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.text.Html.ImageGetter;
import android.text.Spanned;
import android.util.AttributeSet;
import android.widget.TextView;

/**
 * XXX does not support android:drawable, only current app packaged icons
 *
 * Use it with strings like <string name="text"><![CDATA[Some text <img src="some_image"></img> with image in between]]></string>
 * assuming there is @drawable/some_image in project files
 *
 * Must be accompanied by styleable
 * <declare-styleable name="HtmlTextView">
 *    <attr name="android:text" />
 * </declare-styleable>
 */

public class HtmlTextView extends TextView {

    public HtmlTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HtmlTextView);
        String html = context.getResources().getString(typedArray.getResourceId(R.styleable.HtmlTextView_android_text, 0));
        typedArray.recycle();

        Spanned spannedFromHtml = Html.fromHtml(html, new DrawableImageGetter(), null);
        setText(spannedFromHtml);
    }

    private class DrawableImageGetter implements ImageGetter {
        @Override
        public Drawable getDrawable(String source) {
            Resources res = getResources();
            int drawableId = res.getIdentifier(source, "drawable", getContext().getPackageName());
            Drawable drawable = res.getDrawable(drawableId, getContext().getTheme());

            int size = (int) getTextSize();
            int width = size;
            int height = size;

//            int width = drawable.getIntrinsicWidth();
//            int height = drawable.getIntrinsicHeight();

            drawable.setBounds(0, 0, width, height);
            return drawable;
        }
    }
}

rastrear actualizaciones, si hay alguna, en https://gist.github.com/logcat/64234419a935f1effc67


0
2018-01-05 09:59