Dado el siguiente HTML:
<p>This is text and this is an image <img src="http://www.example.com/image.jpg" />.</p>
¿Es posible renderizar la imagen? Cuando uso este fragmento:, mContentText.setText(Html.fromHtml(text));
obtengo un cuadro cian con bordes negros, lo que me lleva a creer que un TextView tiene alguna idea de lo que es una etiqueta img.
Respuestas:
Si echas un vistazo a la documentación
Html.fromHtml(text)
, verás que dice:Si no desea hacer este reemplazo usted mismo, puede usar el otro
Html.fromHtml()
método que toma unHtml.TagHandler
y unHtml.ImageGetter
como argumentos, así como el texto para analizar.En su caso, podría analizar
null
como para elHtml.TagHandler
pero necesitaría implementar su propioHtml.ImageGetter
ya que no hay una implementación predeterminada.Sin embargo, el problema que tendrá es que
Html.ImageGetter
debe ejecutarse de forma sincrónica y, si está descargando imágenes de la web, probablemente querrá hacerlo de forma asincrónica. Si puede agregar las imágenes que desea mostrar como recursos en su aplicación, suImageGetter
implementación se vuelve mucho más simple. Podrías salirte con la tuya con algo como: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, probablemente querrá encontrar algo más inteligente para mapear cadenas de origen a ID de recursos.
fuente
Lo he implementado en mi aplicación, tomado referencia del pskink .thanx mucho
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 hacerlo usando la clase ResolveInfo
compruebe que su archivo sea compatible con 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; } }
fuente
Esto es lo que yo uso, que no necesita que le pongas énfasis a los nombres de tus recursos y buscará los recursos dibujables primero en los recursos de tus aplicaciones y luego en los recursos de Android 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 utilizar 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);
fuente
source
puede ser nulo, ygetIdentifier()
en este caso se bloquea. Mejor agregue un cheque explícito.Me enfrenté al mismo problema y encontré una solución bastante limpia: después de Html.fromHtml () puede ejecutar una AsyncTask que itera sobre todas las etiquetas, recupera las imágenes y luego las muestra.
Aquí puede encontrar algún código que puede usar (pero necesita algo de personalización): https://gist.github.com/1190397
fuente
Usé la respuesta de Dave Webb pero la simplifiqué un poco. Siempre que 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 jugar con cadenas de origen.Lo que hice fue usar el ID de recurso como una cadena de origen:
final String img = String.format("<img src=\"%s\"/>", R.drawable.your_image); final String html = String.format("Image: %s", img);
y utilícelo 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);
fuente
También puede escribir su propio analizador para extraer la URL de todas las imágenes y luego crear dinámicamente nuevas vistas de imágenes y pasar las URL.
fuente
Además, si desea realizar el reemplazo usted mismo, el personaje que debe buscar es [].
Pero si estás usando Eclipse, se asustará cuando escribas esa letra en una declaración [reemplazar] diciéndote que entra en conflicto con Cp1252 - este es un error de Eclipse. Para solucionarlo, ve a
y seleccione
[UTF-8]
fuente
En caso de que alguien piense que los recursos deben ser declarativos y usar Spannable para múltiples idiomas es un desastre, hice una vista personalizada
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; } } }
realizar un seguimiento de las actualizaciones, si las hay, en https://gist.github.com/logcat/64234419a935f1effc67
fuente
KOTLIN
También existe la posibilidad de utilizar
sufficientlysecure.htmltextview.HtmlTextView
Use como se muestra a continuación en los archivos gradle:
Archivo de proyecto gradle:
repositories { jcenter() }
Archivo gradle de la aplicación:
dependencies { implementation 'org.sufficientlysecure:html-textview:3.9' }
Dentro del archivo xml reemplace su textView con:
<org.sufficientlysecure.htmltextview.HtmlTextView android:id="@+id/allNewsBlockTextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="2dp" android:textColor="#000" android:textSize="18sp" app:htmlToString="@{detailsViewModel.selectedText}" />
La última línea de arriba es si usa adaptadores de enlace donde el código será como:
@BindingAdapter("htmlToString") fun bindTextViewHtml(textView: HtmlTextView, htmlValue: String) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { textView.setHtml( htmlValue, HtmlHttpImageGetter(textView, "n", true) ); } else { textView.setHtml( htmlValue, HtmlHttpImageGetter(textView, "n", true) ); } }
Más información de la página de github y muchas gracias a los autores !!!!!
fuente