Учитывая следующий HTML:
<p>This is text and this is an image <img src="http://www.example.com/image.jpg" />.</p>
Можно ли сделать рендер изображения? При использовании этого фрагмента: mContentText.setText(Html.fromHtml(text));
я получаю голубое поле с черными границами, что наводит меня на мысль, что TextView имеет некоторое представление о том, что такое тег img.
Ответы:
Если вы посмотрите документацию,
Html.fromHtml(text)
вы увидите, что там написано:Если вы не хотите , чтобы сделать эту замену себе , что вы можете использовать другой
Html.fromHtml()
метод , который принимаетHtml.TagHandler
и вHtml.ImageGetter
качестве аргументов, а также текст для синтаксического анализа.В вашем случае вы можете проанализировать
null
как для,Html.TagHandler
но вам нужно будет реализовать свою собственную,Html.ImageGetter
поскольку реализации по умолчанию нет.Однако проблема, с которой вы столкнетесь, заключается в том, что вам
Html.ImageGetter
необходимо работать синхронно, и если вы загружаете изображения из Интернета, вы, вероятно, захотите сделать это асинхронно. Если вы можете добавить любые изображения, которые хотите отображать в качестве ресурсов в своем приложении, вашаImageGetter
реализация станет намного проще. Вам может сойти с рук что-то вроде: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; } };
Вы, вероятно, захотите придумать что-нибудь более умное для сопоставления исходных строк с идентификаторами ресурсов.
источник
Я реализовал в своем приложении, взял ссылку на pskink. Спасибо большое
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); } } } }
Как указано ниже в комментарии @rpgmaker, я добавил этот ответ
да, вы можете использовать класс ResolveInfo
проверьте, поддерживается ли ваш файл уже установленными приложениями или нет
используя приведенный ниже код:
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; } }
источник
Это то, что я использую, что не требует от вас жесткой привязки имен ресурсов и будет искать доступные ресурсы сначала в ресурсах ваших приложений, а затем в стандартных ресурсах Android, если ничего не было найдено, что позволяет использовать значки по умолчанию и т.
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; } } }
Что можно использовать как таковое (пример):
String myHtml = "This will display an image to the right <img src='ic_menu_more' />"; myTextview.setText(Html.fromHtml(myHtml, new ImageGetter(), null);
источник
source
может быть null иgetIdentifier()
в этом случае произойдет сбой. Лучше добавить явную проверку.Я столкнулся с той же проблемой и нашел довольно чистое решение: после Html.fromHtml () вы можете запустить AsyncTask, который выполняет итерацию по всем тегам, извлекает изображения и затем отображает их.
Здесь вы можете найти код, который можно использовать (но он требует некоторой настройки): https://gist.github.com/1190397
источник
Я использовал ответ Дэйва Уэбба, но немного упростил его. Пока идентификаторы ресурсов останутся неизменными во время выполнения в вашем варианте использования, на самом деле нет необходимости писать свою собственную реализацию класса
Html.ImageGetter
и возиться с исходными строками.Я использовал идентификатор ресурса в качестве исходной строки:
final String img = String.format("<img src=\"%s\"/>", R.drawable.your_image); final String html = String.format("Image: %s", img);
и используйте его напрямую:
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);
источник
Вы также можете написать свой собственный синтаксический анализатор, который будет извлекать URL-адреса всех изображений, а затем динамически создавать новые просмотры изображений и передавать URL-адреса.
источник
Кроме того, если вы все же хотите произвести замену самостоятельно, вам нужно будет найти символ [].
Но если вы используете Eclipse, он испугается, когда вы введете эту букву в оператор [replace], сообщив вам, что он конфликтует с Cp1252 - это ошибка Eclipse. Чтобы исправить это, перейдите в
и выберите
[UTF-8]
источник
Если кто-то думает, что ресурсы должны быть декларативными, а использование Spannable для нескольких языков - беспорядок, я сделал несколько настраиваемых представлений
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; } } }
отслеживать обновления, если таковые имеются, на https://gist.github.com/logcat/64234419a935f1effc67
источник
КОТЛИН
Также есть возможность использовать
sufficientlysecure.htmltextview.HtmlTextView
Используйте, как показано ниже, в файлах Gradle:
Файл проекта gradle:
repositories { jcenter() }
Файл приложения Gradle:
dependencies { implementation 'org.sufficientlysecure:html-textview:3.9' }
Внутри xml файла замените свой textView на:
<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}" />
Последняя строка выше - если вы используете адаптеры привязки, код будет примерно таким:
@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) ); } }
Больше информации со страницы github и большое спасибо авторам !!!!!
источник