Html.ImageGetter TextView

时间:2013-04-23 21:13:41

标签: java android textview

所以我使用ImageGetter来显示JSON博客文章中的图像。我在日志中获取了正确的源,但是当URL达到setBounds时URL会发生变化。有什么想法吗?

代码:

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;
    }
};

尝试前的“来源”是

http://www.domain.com/images_blog/feature.png

但是在捕获中错误是:

无法解码流:

java.io.FileNotFoundException: /http:/www.domain.com/images_blog/feature.png : open failed: ENOENT (No such file or directory)

5 个答案:

答案 0 :(得分:47)

最简单的解决方案是:

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);
            }
        }
    }
}

在图像下载后重新布局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);

如果有人知道更好的解决方案,请告诉我

答案 1 :(得分:2)

如果你有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);
        } 

答案 2 :(得分:1)

这个答案可能有助于某人。我使用Jsoup从字符串中提取<Img/>标记,然后在ImageView<p> Textview中显示图像。结果是根据我的需要。我也使用Universal Image Loader Libaray在ImageView中加载图像然后我以编程方式将视图添加到我的案例布局中的布局是线性布局,所以我做了一个帮助类并传递内容,html字符串和线性布局作为参数。

在项目中添加jsoup。

compile 'org.jsoup:jsoup:1.9.2'

这里有一些片段。

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;
}
}

我希望我的回答会对某人有所帮助。

答案 3 :(得分:1)

使用GlideCoroutines的替代解决方案,假设不需要重试:

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
        }
    }
}

FragmentActivity中使用HtmlCompat

val imageGetter = HtmlImageGetter(lifecycleScope, resources, glide, htmlTextView)
val styledText = HtmlCompat.fromHtml(htmlString, flags, imageGetter, null)
htmlTextView.text = styledText

答案 4 :(得分:0)

如果您拥有mTV(我是说TextView),则可以根据其尺寸(mTv.getWidth()和mTv.getHeight())以及所创建位图的尺寸(bitmap.getWidth()和bitmap.getHeight())进行计算),并将这些值设置为TextView(mTv)的新尺寸。