java Html.ImageGetter 文本视图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16179285/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Html.ImageGetter TextView
提问by JMP
So Im using ImageGetter to display the images from JSON blog posts. Im getting the correct source in the log but the URL changes when it reaches setBounds. Any ideas?
所以我使用 ImageGetter 来显示来自 JSON 博客文章的图像。我在日志中获得了正确的来源,但是当它到达 setBounds 时 URL 会发生变化。有任何想法吗?
Code:
代码:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_blog_view);
Intent intent = getIntent();
Uri blogUri = intent.getData();
mPost = blogUri.toString();
mUrl = getIntent().getStringExtra("mUrl");
TextView textView = (TextView) findViewById(R.id.scrollView1);
textView.setText(Html.fromHtml(mPost, imgGetter, null));
}
private ImageGetter imgGetter = new ImageGetter(){
@Override
public Drawable getDrawable(String source){
Drawable drawable = Drawable.createFromPath(source);
try {
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
}catch (NullPointerException e){
logException(e);
}
return drawable;
}
};
The "source" before the try is
尝试之前的“来源”是
http://www.domain.com/images_blog/feature.png
http://www.domain.com/images_blog/feature.png
but in the catch the error is:
但在捕获错误是:
Unable to decode stream:
无法解码流:
java.io.FileNotFoundException: /http:/www.domain.com/images_blog/feature.png : open failed: ENOENT (No such file or directory)
回答by pskink
the easiest solution is:
最简单的解决方案是:
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import org.pskink.soom.R;
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 TestImageGetter 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.test_image_getter);
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://developer.android.com/assets/images/icon_search.png\">";
Spanned spanned = Html.fromHtml(source, 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);
}
}
}
}
there is one not quite elegant way to re-layout a TextView after image downloading:
有一种不太优雅的方法可以在图像下载后重新布局 TextView:
// 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);
if anybody knows better solution please let me know
如果有人知道更好的解决方案,请告诉我
回答by Mike Cwiklinski
If you have mTV (I mean TextView), you can calculate based on its dimensions (mTv.getWidth() and mTv.getHeight()) and dimension of created bitmap (bitmap.getWidth() and bitmap.getHeight()) and set these values as new dimensions of TextView (mTv).
如果你有 mTV(我的意思是 TextView),你可以根据它的尺寸(mTv.getWidth() 和 mTv.getHeight())和创建的位图的尺寸(bitmap.getWidth() 和 bitmap.getHeight())计算并设置这些值作为 TextView (mTv) 的新维度。
if (bitmap != null) {
BitmapDrawable d = new BitmapDrawable(bitmap);
mDrawable.addLevel(1, 1, d);
int width = mTv.getWidth() < bitmap.getWidth() ? mTv.getWidth() : bitmap.getWidth();
int height = bitmap.getHeight() * width / bitmap.getWidth();
mDrawable.setBounds(0, 0, width, height);
mDrawable.setLevel(1);
// i don't know yet a better way to refresh TextView
// mTv.invalidate() doesn't work as expected
// but we can calculate new TextView dimensions
mTv.setHeight(height);
CharSequence t = mTv.getText();
mTv.setText(t);
}
回答by Zeeshan Shabbir
This answer may help someone. I used Jsoup to extract <Img/>
tag out of the string then i show the image in ImageView
and <p>
in Textview
. Results was according to what i needed. Also i used Universal Image Loader Libaray to load images in ImageView
Then i added view programmatically to the layout in my case layout was the linearlayout so i made a helper class and passed content,html string and linear layout as the parameter.
这个答案可能对某人有所帮助。我用Jsoup来提取<Img/>
标记出字符串的话,我展示形象ImageView
和<p>
在Textview
。结果是根据我需要的。此外,我使用 Universal Image Loader Libaray 加载图像,ImageView
然后我以编程方式将视图添加到布局中,在我的案例布局中,布局是线性布局,因此我创建了一个辅助类并传递了内容、html 字符串和线性布局作为参数。
add jsoup in your project.
在您的项目中添加 jsoup。
compile 'org.jsoup:jsoup:1.9.2'
Here some snippet.
这里有一些片段。
public class PostContentHandler {
Context context;
String content;
LinearLayout linearLayout;
public PostContentHandler(Context context, String content, LinearLayout linearLayout) {
this.context = context;
this.content = content;
this.linearLayout = linearLayout;
}
public void setContentToView() {
//custom font
Typeface bitterBoldFont = Typeface.createFromAsset(context.getAssets(), "fonts/Bitter-Regular.otf");
List<String> p = new ArrayList<>();
List<String> src = new ArrayList<>();
List<String> li = new ArrayList<>();
Document doc = Jsoup.parse(content);
Elements elements = doc.getAllElements();
for (Element element : elements) {
Tag tag = element.tag();
if (tag.getName().matches("h[1-6]{1}")) {
String heading = element.select(tag.getName().toString()).text();
TextView textView = new TextView(context);
textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) textView.getLayoutParams();
int top = (int) context.getResources().getDimension(R.dimen.heading_margin_top);
int start = (int) context.getResources().getDimension(R.dimen.content_margin);
int end = (int) context.getResources().getDimension(R.dimen.content_margin);
params.setMargins(start, top, end, 0);
textView.setTextSize(20);
textView.setTypeface(bitterBoldFont);
textView.setText(heading);
textView.setTextColor(context.getResources().getColor(R.color.black));
linearLayout.addView(textView);
}
if (tag.getName().equalsIgnoreCase("p")) {
element.select("img").remove();
String body = element.html();
TextView textView = new TextView(context);
textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) textView.getLayoutParams();
int top = (int) context.getResources().getDimension(R.dimen.heading_margin_top);
int start = (int) context.getResources().getDimension(R.dimen.content_margin);
int end = (int) context.getResources().getDimension(R.dimen.content_margin);
params.setMargins(start, top, end, 0);
textView.setTypeface(bitterBoldFont);
textView.setLinksClickable(true);
textView.setAutoLinkMask(Linkify.WEB_URLS);
textView.setText(Html.fromHtml(body));
textView.setTextColor(context.getResources().getColor(R.color.content_color));
linearLayout.addView(textView);
p.add(body);
}
if (tag.getName().equalsIgnoreCase("ol")) {
String ol = element.select(tag.getName().toString()).outerHtml();
TextView textView = new TextView(context);
textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) textView.getLayoutParams();
params.setMarginStart((int) context.getResources().getDimension(R.dimen.content_margin));
int top = (int) context.getResources().getDimension(R.dimen.heading_margin_top);
int start = (int) context.getResources().getDimension(R.dimen.content_margin);
int end = (int) context.getResources().getDimension(R.dimen.content_margin);
params.setMargins(start, top, end, 0);
textView.setTypeface(bitterBoldFont);
textView.setLinksClickable(true);
textView.setAutoLinkMask(Linkify.WEB_URLS);
textView.setTextColor(context.getResources().getColor(R.color.content_color));
textView.setText(Html.fromHtml(ol, null, new MyTagHandler()));
linearLayout.addView(textView);
}
if (tag.getName().equalsIgnoreCase("ul")) {
String ul = element.select(tag.getName().toString()).outerHtml();
TextView textView = new TextView(context);
textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) textView.getLayoutParams();
int top = (int) context.getResources().getDimension(R.dimen.heading_margin_top);
int start = (int) context.getResources().getDimension(R.dimen.content_margin);
int end = (int) context.getResources().getDimension(R.dimen.content_margin);
params.setMargins(start, top, end, 0);
textView.setTypeface(bitterBoldFont);
textView.setLinksClickable(true);
textView.setAutoLinkMask(Linkify.WEB_URLS);
textView.setTextColor(context.getResources().getColor(R.color.content_color));
textView.setText(Html.fromHtml(ul, null, new MyTagHandler()));
linearLayout.addView(textView);
}
if (tag.getName().equalsIgnoreCase("img")) {
String url = element.select("img").attr("src");
final ImageView imageView = new ImageView(context);
imageView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
final ProgressBar progressBar = new ProgressBar(context);
linearLayout.addView(progressBar);
progressBar.setVisibility(View.GONE);
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(url, imageView, new SimpleImageLoadingListener() {
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage);
progressBar.setVisibility(View.INVISIBLE);
int height = loadedImage.getHeight();
imageView.getLayoutParams().height = getScreenWidth();
imageView.setAdjustViewBounds(true);
imageView.requestLayout();
}
@Override
public void onLoadingStarted(String imageUri, View view) {
super.onLoadingStarted(imageUri, view);
progressBar.setVisibility(View.VISIBLE);
}
});
linearLayout.addView(imageView);
src.add(url);
}
}
}
public static int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
}
I hope my answer will help someone.
我希望我的回答对某人有所帮助。
回答by Marco RS
An alternative solution using Glide
and Coroutines
with the assumption that a retry is not required:
使用Glide
和Coroutines
假设不需要重试的替代解决方案:
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.text.Html
import android.widget.TextView
import androidx.lifecycle.LifecycleCoroutineScope
import com.bumptech.glide.RequestManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.math.roundToInt
class HtmlImageGetter(
private val scope: LifecycleCoroutineScope,
private val res: Resources,
private val glide: RequestManager,
private val htmlTextView: TextView
) : Html.ImageGetter {
override fun getDrawable(url: String): Drawable {
val holder = BitmapDrawablePlaceHolder(res, null)
scope.launch(Dispatchers.IO) {
runCatching {
val bitmap = glide
.asBitmap()
.load(url)
.submit()
.get()
val drawable = BitmapDrawable(res, bitmap)
val scale = 1.25 // This makes the image scale in size.
val width = (drawable.intrinsicWidth * scale).roundToInt()
val height = (drawable.intrinsicHeight * scale).roundToInt()
drawable.setBounds(0, 0, width, height)
holder.setDrawable(drawable)
holder.setBounds(0, 0, width, height)
withContext(Dispatchers.Main) { htmlTextView.text = htmlTextView.text }
}
}
return holder
}
internal class BitmapDrawablePlaceHolder(res: Resources, bitmap: Bitmap?) : BitmapDrawable(res, bitmap) {
private var drawable: Drawable? = null
override fun draw(canvas: Canvas) {
drawable?.run { draw(canvas) }
}
fun setDrawable(drawable: Drawable) {
this.drawable = drawable
}
}
}
In a Fragment
or Activity
use with HtmlCompat
在 aFragment
或Activity
与HtmlCompat
val imageGetter = HtmlImageGetter(lifecycleScope, resources, glide, htmlTextView)
val styledText = HtmlCompat.fromHtml(htmlString, flags, imageGetter, null)
htmlTextView.text = styledText