เป็นไปได้ไหมที่จะแสดงภาพแบบอินไลน์จาก html ใน Android TextView


87

รับ 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 คืออะไร


1
ชำระเงินโพสต์ของฉัน @ javatechig.com javatechig.com/2013/04/07/how-to-display-html-in-android-view
Nilanchal

คำตอบ:


126

หากคุณดูเอกสารประกอบHtml.fromHtml(text)คุณจะเห็นว่า:

<img>แท็กใด ๆใน HTML จะแสดงเป็นรูปภาพแทนที่ทั่วไปซึ่งโปรแกรมของคุณสามารถผ่านและแทนที่ด้วยรูปภาพจริงได้

หากคุณไม่ต้องการทำการแทนที่ด้วยตัวเองคุณสามารถใช้วิธีอื่นHtml.fromHtml()ซึ่งใช้อาร์กิวเมนต์Html.TagHandlerและ an Html.ImageGetteras เช่นเดียวกับข้อความในการแยกวิเคราะห์

ในกรณีของคุณคุณสามารถแยก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;
    }
};

คุณอาจต้องการหาสิ่งที่ชาญฉลาดกว่าสำหรับการแมปสตริงแหล่งที่มากับรหัสทรัพยากร


4
ตกลง. ฉันพบว่าการใช้ WebView แทนนั้นง่ายกว่า ฉันเห็นว่าเทคนิคของคุณมีประโยชน์สำหรับสถานการณ์อื่น ๆ ที่คล้ายกัน ขอบคุณ!
Gunnar Lium

1
วิธีที่ชาญฉลาดกว่าในการรับรหัสทรัพยากรจากชื่อคือการใช้ Resources.getIdentifier (ชื่อสตริง, String defType, String defPackage)
Timuçin

@Gunnar Lium ... แต่ i8mage ไม่แสดงใน webview .. !! ช่วยด้วย ??
kgandroid

ถ้าภาพอยู่ในเซิร์ฟเวอร์แล้วเราจะรับภาพได้อย่างไร…ในกรณีของฉันภาพเป็นแบบไดนามิก…ฉันไม่สามารถใช้มุมมองภาพอื่น ๆ ได้เพราะไม่แน่ใจว่าจะต้องเป็นภาพ…
Sourav Roy

19

ฉันได้ติดตั้งในแอปของฉันได้รับการรับรองจาก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 ฉันได้เพิ่มคำตอบนี้

ใช่คุณสามารถทำได้โดยใช้คลาสResolveInfo

ตรวจสอบว่าไฟล์ของคุณรองรับกับแอพที่ติดตั้งไว้แล้วหรือไม่

โดยใช้รหัสด้านล่าง:

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

1
เฮ้จุดประสงค์ของ "addlevel" และ "setLevel" คืออะไรกันแน่?
Aeefire

มีวิธีการรวมภาพจากส่วนกลางหรือไม่? จะเป็นการดีถ้าเราสามารถแตะและแสดงในแอพดูรูปภาพที่เราติดตั้งไว้
Aspiring Dev

ฉันคิดว่าคุณลืมบริบทสำหรับคำถามของฉัน ฉันรู้วิธีเปิดไฟล์รูปภาพด้วยแอพโปรแกรมดูรูปภาพ แต่คำตอบของคุณใส่บิตแมปไว้ใน TextView และเท่าที่ฉันบอกได้ว่าไม่มีทางที่จะเข้าใจได้เมื่อผู้ใช้แตะรูปภาพที่ต้องการภายใน นี่เป็นปัญหามากกว่าหากคุณมีรูปภาพจำนวนมากใน textview มีวิธีทำไหม?
Aspiring Dev

แต่ปัญหาหนึ่งคือมันเลื่อนช้ามากเราจะทำอะไรได้ไหม?
Pratik Jamariya

พยายามเพิ่มผู้ฟังสกรอลล์ที่ราบรื่น
madhu527

16

นี่คือสิ่งที่ฉันใช้ซึ่งไม่จำเป็นต้องให้คุณไม่ยอมใครง่ายๆชื่อทรัพยากรของคุณและจะมองหาทรัพยากรที่ดึงได้ก่อนในทรัพยากรแอปของคุณจากนั้นในทรัพยากร 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);

การผสมผสานนี้จะสมบูรณ์แบบกับการดึงข้อมูลอินเทอร์เน็ตจาก AsyncTask
Francis Rodrigues

1
ขอบคุณ! มันช่วยแก้ปัญหาของฉันได้ ฉันต้องการเพียงภาพในเครื่องดังนั้นเพียงแค่วางลงในโฟลเดอร์ที่วาดได้และอย่าลืมลบส่วนขยายของภาพเมื่อเรียกจาก html
Dody Rachmat Wicaksono

ขอบคุณ! แต่ระวังsourceอาจเป็นโมฆะและgetIdentifier()ขัดข้องในกรณีนี้ เพิ่มการตรวจสอบที่ชัดเจนดีกว่า
gmk57

5

ฉันประสบปัญหาเดียวกันและพบวิธีแก้ปัญหาที่ค่อนข้างสะอาด: หลังจาก Html.fromHtml () คุณสามารถเรียกใช้ AsyncTask ที่วนซ้ำบนแท็กทั้งหมดดึงรูปภาพแล้วแสดง

ที่นี่คุณจะพบโค้ดบางอย่างที่ใช้ได้ (แต่ต้องปรับแต่งบางอย่าง): https://gist.github.com/1190397


3

ฉันใช้คำตอบของ Dave Webb แต่ทำให้ง่ายขึ้นเล็กน้อย ตราบใดที่รหัสทรัพยากรจะยังคงเหมือนเดิมในระหว่างรันไทม์ในกรณีการใช้งานของคุณคุณไม่จำเป็นต้องเขียนคลาสของคุณเองเพื่อนำไปใช้งานHtml.ImageGetterและยุ่งเกี่ยวกับสตริงที่มา

สิ่งที่ฉันทำคือใช้รหัสทรัพยากรเป็นสตริงต้นทาง:

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

1

คุณยังสามารถเขียนโปรแกรมแยกวิเคราะห์ของคุณเองเพื่อดึง URL ของรูปภาพทั้งหมดจากนั้นสร้างมุมมองภาพใหม่แบบไดนามิกและส่งใน URL


1

นอกจากนี้หากคุณต้องการแทนที่ตัวเองตัวละครที่คุณต้องมองหาคือ []

แต่ถ้าคุณใช้ Eclipse มันจะประหลาดเมื่อคุณพิมพ์ตัวอักษรนั้นลงในคำสั่ง [แทนที่] โดยบอกคุณว่ามันขัดแย้งกับ Cp1252 - นี่คือบั๊ก Eclipse หากต้องการแก้ไขให้ไปที่

หน้าต่าง -> การตั้งค่า -> ทั่วไป -> พื้นที่ทำงาน -> การเข้ารหัสไฟล์ข้อความ,

และเลือก [UTF-8]


1

คอตลิน

นอกจากนี้ยังมีความเป็นไปได้ที่จะใช้ sufficientlysecure.htmltextview.HtmlTextView

ใช้ดังต่อไปนี้ในไฟล์ gradle:

ไฟล์ Gradle โครงการ:

repositories {
    jcenter()
}

ไฟล์ App gradle:

dependencies {
implementation 'org.sufficientlysecure:html-textview:3.9'
}

ภายในไฟล์ xml แทนที่ textView ของคุณด้วย:

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

บรรทัดสุดท้ายด้านบนคือถ้าคุณใช้ Binding adapters ซึ่งรหัสจะเป็นดังนี้:

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

ข้อมูลเพิ่มเติมจากหน้า github และขอขอบคุณผู้เขียน !!!!!


0

ในกรณีที่มีคนคิดว่าทรัพยากรต้องมีการเปิดเผยและการใช้ 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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.