代码之家  ›  专栏  ›  技术社区  ›  Gunnar Lium

是否可以在Android文本视图中显示HTML中的内联图像?

  •  81
  • Gunnar Lium  · 技术社区  · 14 年前

    给定以下HTML:

    <p>This is text and this is an image <img src="http://www.example.com/image.jpg" />.</p>

    是否可以进行图像渲染?使用此代码段时: mContentText.setText(Html.fromHtml(text)); ,我得到了一个带有黑色边框的青色框,这让我相信一个文本视图对img标签有一定的了解。

    8 回复  |  直到 8 年前
        1
  •  122
  •   David Webb    14 年前

    如果你看一下 documentation for Html.fromHtml(text) 你会看到上面写着:

    任何 <img> HTML中的标记将显示为一个通用的替换图像,然后您的程序可以通过该图像替换为真实图像。

    如果你不想自己做这个替换,你可以用 the other Html.fromHtml() method 这需要一个 Html.TagHandler 和一个 Html.ImageGetter 以及要分析的文本。

    在您的案例中,您可以分析 null 至于 塔克汉德勒 但你需要实现你自己的 html.imagegetter 因为没有默认的实现。

    然而,你将面临的问题是 html.imagegetter 需要同步运行,如果您要从Web下载图像,您可能需要异步运行。如果可以添加任何要在应用程序中显示为资源的图像, 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。

        2
  •  16
  •   madhu527    8 年前

    我已经在我的应用程序中实现了,从 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 comment,我添加了这个答案。

    是的,你可以用 解决方案信息

    检查是否已安装的应用程序支持您的文件

    使用以下代码:

    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;
        }
    }
    
        3
  •  12
  •   drawk    10 年前

    这就是我所使用的,它不需要你硬编码你的资源名称,并且会先在你的应用程序资源中寻找可提取的资源,然后在没有找到任何东西的情况下寻找库存的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);
    
        4
  •  5
  •   Julian    13 年前

    我也遇到了同样的问题,我找到了一个非常干净的解决方案:在html.fromhtml()之后,您可以运行一个异步任务,对所有标记进行迭代,获取图像,然后显示它们。

    在这里,您可以找到一些可以使用的代码(但它需要一些自定义): https://gist.github.com/1190397

        5
  •  3
  •   Blacklight    11 年前

    我用了戴夫·韦伯的回答,但简化了一点。只要资源ID在运行时在用例中保持不变,就不需要编写自己的类实现 Html.ImageGetter 和干扰源字符串。

    我所做的是使用资源ID作为源字符串:

    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);
    
        6
  •  1
  •   Falmarri    14 年前

    您还可以编写自己的解析器来提取所有图像的URL,然后动态创建新的ImageView并传入URL。

        7
  •  1
  •   akjoshi HCP    12 年前

    另外,如果你想自己做替换,你需要寻找的角色是[_?]

    但是,如果您使用Eclipse,当您在[replace]语句中键入该字母,并告诉您它与CP1252冲突时,它将异常异常——这是Eclipse错误。要修复它,请转到

    窗口->首选项->常规->工作区->文本文件编码,

    并选择 [UTF-8]

        8
  •  0
  •   logcat    9 年前

    如果有人认为资源必须是声明性的,并且对多种语言使用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