Android TextView에서 HTML의 인라인 이미지를 표시 할 수 있습니까?
다음 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)
살펴보면 다음과 같이 표시됩니다.
<img>
HTML의 모든 태그는 프로그램이 통과하여 실제 이미지로 대체 할 수있는 일반 대체 이미지로 표시됩니다.
이 대체를 직접 수행하지 않으려면 구문 분석 할 텍스트뿐만 아니라 및 as 인수를 사용 하는 다른 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;
}
};
그래도 소스 문자열을 리소스 ID에 매핑하는 데 더 스마트 한 방법을 찾고 싶을 것입니다.
나는 내 앱에서 구현했으며 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);
}
}
}
}
아래 @rpgmaker 코멘트에 따라이 답변을 추가했습니다.
yes you can do using ResolveInfo class
check your file is supported with already installed apps or not
using below code:
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;
}
}
This is what I use, which does not need you to hardcore your resource names and will look for the drawable resources first in your apps resources and then in the stock android resources if nothing was found - allowing you to use default icons and such.
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;
}
}
}
Which can be used as such (example):
String myHtml = "This will display an image to the right <img src='ic_menu_more' />";
myTextview.setText(Html.fromHtml(myHtml, new ImageGetter(), null);
I faced the same problem and I've found a pretty clean solution: After Html.fromHtml() you can run an AsyncTask that iterates over all the tags, fetches the images and then displays them.
Here you can find some code that you can use (but it needs some customization): https://gist.github.com/1190397
I used Dave Webb's answer but simplified it a bit. As long as the resource IDs will stay the same during runtime in your use-case, there's not really a need to write your own class implementing Html.ImageGetter
and mess around with source-strings.
What I did was using the resource ID as a source-string:
final String img = String.format("<img src=\"%s\"/>", R.drawable.your_image);
final String html = String.format("Image: %s", img);
and use it directly:
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);
You could also write your own parser to pull the URL of all the images and then dynamically create new imageviews and pass in the urls.
Also, if you do want to do the replacement yourself, the character you need to look for is [  ].
But if you're using Eclipse, it will freak out when you type that letter into a [replace] statement telling you it conflicts with Cp1252 - this is an Eclipse bug. To fix it, go to
Window -> Preferences -> General -> Workspace -> Text file encoding,
and select [UTF-8]
In case somebody think that resources must be declarative and using Spannable for multiple languages is a mess, I did some custom view
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;
}
}
}
track updates, if any, at https://gist.github.com/logcat/64234419a935f1effc67
'developer tip' 카테고리의 다른 글
뷰가 좋은 이유는 무엇입니까? (0) | 2020.09.24 |
---|---|
Bash에서 따옴표로 묶인 문자열에서 줄 바꿈을 어떻게 유지합니까? (0) | 2020.09.24 |
.NET에서 TimeSpan 곱하기 (0) | 2020.09.24 |
String과 String.valueOf 로의 캐스팅의 차이점 (0) | 2020.09.24 |
PHP에서 세 점 (…)의 의미 (0) | 2020.09.24 |