Biorąc pod uwagę następujący kod HTML:
<p>This is text and this is an image <img src="http://www.example.com/image.jpg" />.</p>
Czy można renderować obraz? Korzystając z tego fragmentu kodu:, mContentText.setText(Html.fromHtml(text));
otrzymuję niebieskie pole z czarnymi obramowaniami, co prowadzi mnie do przekonania, że TextView ma pewne pojęcie o tym, czym jest tag img.
Odpowiedzi:
Jeśli spojrzysz na dokumentację
Html.fromHtml(text)
, zobaczysz, że mówi:Jeśli nie chcesz wykonywać tej zamiany samodzielnie, możesz użyć innej
Html.fromHtml()
metody, która przyjmuje argumenty anHtml.TagHandler
i anHtml.ImageGetter
jako argumenty, a także tekst do przeanalizowania.W twoim przypadku możesz przeanalizować
null
jak w przypadku,Html.TagHandler
ale musisz zaimplementować własną,Html.ImageGetter
ponieważ nie ma domyślnej implementacji.Jednak problem, który będziesz mieć, polega na tym, że
Html.ImageGetter
musi działać synchronicznie, a jeśli pobierasz obrazy z Internetu, prawdopodobnie będziesz chciał to zrobić asynchronicznie. Jeśli możesz dodać obrazy, które chcesz wyświetlić jako zasoby w aplikacji,ImageGetter
implementacja stanie się znacznie prostsza. Możesz uciec z czymś takim: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; } };
Prawdopodobnie jednak chciałbyś wymyślić coś mądrzejszego do mapowania ciągów źródłowych na identyfikatory zasobów.
źródło
Zaimplementowałem w swojej aplikacji, bardzo korzystałem z pskink .thanx
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); } } } }
Zgodnie z komentarzem @rpgmaker dodałem tę odpowiedź
tak, możesz to zrobić używając klasy ResolveInfo
sprawdź, czy Twój plik jest obsługiwany przez już zainstalowane aplikacje, czy nie
używając poniższego kodu:
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; } }
źródło
To jest to, czego używam, co nie wymaga od ciebie hardcore'owania nazw zasobów i będzie szukać zasobów do rysowania najpierw w zasobach aplikacji, a następnie w zasobach Androida, jeśli nic nie zostało znalezione - co pozwala na użycie domyślnych ikon i tym podobnych.
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; } } }
Które można wykorzystać jako takie (przykład):
String myHtml = "This will display an image to the right <img src='ic_menu_more' />"; myTextview.setText(Html.fromHtml(myHtml, new ImageGetter(), null);
źródło
source
może być zerowa igetIdentifier()
awarie w tym przypadku. Lepiej dodaj wyraźną kontrolę.Napotkałem ten sam problem i znalazłem całkiem czyste rozwiązanie: po Html.fromHtml () możesz uruchomić AsyncTask, które iteruje po wszystkich tagach, pobiera obrazy, a następnie je wyświetla.
Tutaj znajdziesz kod, którego możesz użyć (ale wymaga to dostosowania): https://gist.github.com/1190397
źródło
Skorzystałem z odpowiedzi Dave'a Webba, ale trochę ją uprościłem. Tak długo, jak identyfikatory zasobów pozostaną takie same podczas działania w Twoim przypadku użycia, tak naprawdę nie ma potrzeby pisania własnej implementacji klasy
Html.ImageGetter
i bałaganu z łańcuchami źródłowymi.To, co zrobiłem, polegało na użyciu identyfikatora zasobu jako ciągu źródłowego:
final String img = String.format("<img src=\"%s\"/>", R.drawable.your_image); final String html = String.format("Image: %s", img);
i użyj go bezpośrednio:
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);
źródło
Możesz także napisać własny parser, aby pobrać adresy URL wszystkich obrazów, a następnie dynamicznie utworzyć nowe widoki obrazów i przekazać je.
źródło
Ponadto, jeśli chcesz dokonać wymiany samodzielnie, postać, której musisz szukać, to [].
Ale jeśli używasz Eclipse, to zwariuje, gdy wpiszesz tę literę do instrukcji [replace], co oznacza, że jest w konflikcie z Cp1252 - to jest błąd Eclipse. Aby to naprawić, przejdź do
i wybierz
[UTF-8]
źródło
W przypadku, gdy ktoś uważa, że zasoby muszą być deklaratywne, a używanie Spannable dla wielu języków jest bałaganem, zrobiłem niestandardowy widok
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; } } }
śledź aktualizacje, jeśli istnieją, na https://gist.github.com/logcat/64234419a935f1effc67
źródło
KOTLIN
Istnieje również możliwość skorzystania
sufficientlysecure.htmltextview.HtmlTextView
Użyj jak poniżej w plikach gradle:
Plik oceny projektu:
repositories { jcenter() }
Plik oceny aplikacji:
dependencies { implementation 'org.sufficientlysecure:html-textview:3.9' }
Wewnątrz pliku xml zamień swój textView na:
<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}" />
Ostatni wiersz powyżej dotyczy użycia adapterów Binding, w których kod będzie wyglądał następująco:
@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) ); } }
Więcej informacji ze strony github i wielkie podziękowania dla autorów !!!!!
źródło