क्या एंड्रॉइड टेक्स्ट व्यू में HTML से इनलाइन छवियों को प्रदर्शित करना संभव है?


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));मुझे ब्लैक बॉर्डर्स के साथ एक सियान बॉक्स मिलता है, जिससे मुझे विश्वास होता है कि टेक्स्टव्यू को कुछ पता है कि आईएमजी टैग क्या है।


जवाबों:


125

यदि आप प्रलेखनHtml.fromHtml(text) पर एक नज़र डालते हैं तो आप देखेंगे कि यह कहता है:

<img>HTML में कोई भी टैग जेनेरिक रिप्लेसमेंट इमेज के रूप में प्रदर्शित होगा जिसे आपका प्रोग्राम वास्तविक इमेज से बदलकर बदल सकता है।

आप इस प्रतिस्थापन खुद नहीं करना चाहते हैं तो आप उपयोग कर सकते हैं अन्य 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 के लिए स्रोत स्ट्रिंग्स की मैपिंग के लिए कुछ अधिक समझदारी चाहते हैं।


4
ठीक है। मैंने पाया कि इसके बजाय केवल एक WebView का उपयोग करना आसान था। मैं आपकी तकनीक को अन्य समान परिदृश्यों के लिए उपयोगी होते हुए देख सकता हूँ, हालाँकि। धन्यवाद!
गुन्नार लियम

1
नाम से रिसोर्स आइडी प्राप्त करने का सबसे आसान तरीका है रिसोर्स.गेटइंटिफायर (स्ट्रिंग नाम, स्ट्रिंग डिफाइप, स्ट्रिंग डीपैकेज) का उपयोग करना।
तैमुकिन

@ गुन्नार लिम ... लेकिन i8mage वेबव्यू में नहीं दिख रहा है .. !! कोई मदद ??
किलोन्ड्रोइड

यदि छवि एक सर्वर में है तो हम छवि कैसे प्राप्त कर सकते हैं ... मेरे मामले में छवि गतिशील है ... मैं अन्य छवि दृश्यों का उपयोग नहीं कर सकता क्योंकि यह निश्चित नहीं है कि एक छवि होनी चाहिए ...
सौरव रॉय

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

क्या छवियों को केंद्रीकृत करने का एक तरीका है? यह भी अच्छा होगा यदि हम उन्हें टैप कर सकें और उन्हें हमारे द्वारा इंस्टॉल किए गए किसी भी इमेज व्यूअर ऐप में दिखा सकें।
आकांक्षी देव

मुझे लगता है कि आप मेरे प्रश्न के संदर्भ को भूल गए। मुझे पता है कि एक छवि दर्शक ऐप के साथ एक छवि फ़ाइल कैसे खोलें, लेकिन आपका जवाब एक टेक्स्ट व्यू के अंदर बिटमैप्स डालता है और जहां तक ​​मैं बता सकता हूं कि जब उपयोगकर्ता इसके अंदर एक विशिष्ट छवि का दोहन कर रहा है, तो समझदारी का कोई रास्ता नहीं है। यदि आप टेक्स्टव्यू के अंदर कई चित्र रखते हैं तो यह एक समस्या है। क्या इसे करने का कोई तरीका है?
देव

लेकिन एक मुद्दा यह है कि यह बहुत धीमा है, क्या हम इसके बारे में कुछ कर सकते हैं?
प्रतीकात्मक जमरिया

चिकनी स्क्रॉल श्रोताओं को जोड़ने की कोशिश करें
मधु ०५२ '

16

यह वही है जो मैं उपयोग करता हूं, जिसके लिए आपको अपने संसाधन नामों को हार्डकोर करने की आवश्यकता नहीं है और यह आपके एप्लिकेशन संसाधनों में और फिर स्टॉक एंड्रॉइड संसाधनों में सबसे पहले ड्रा करने योग्य संसाधनों की तलाश करेगा, अगर कुछ भी नहीं मिला था - आपको डिफ़ॉल्ट आइकन और ऐसे का उपयोग करने की अनुमति देता है।

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 से परिपूर्ण होगा।
फ्रांसिस रोड्रिग्स

1
धन्यवाद! इसने मेरी समस्या हल कर दी। मुझे केवल स्थानीय छवियों की आवश्यकता है, इसलिए बस उन्हें ड्रॉ करने योग्य फ़ोल्डर में छोड़ दें और HTML से कॉल करते समय छवि को हटाने पर सुनिश्चित करें।
डोडी रचमत विसाकोसनो

धन्यवाद! लेकिन इस मामले में सावधान रहना sourceऔर getIdentifier()दुर्घटनाग्रस्त हो सकता है । बेहतर एक स्पष्ट जाँच जोड़ें।
gmk57

5

मैंने एक ही समस्या का सामना किया है और मुझे एक बहुत अच्छा समाधान मिला है: Html.fromHtml () के बाद आप एक AsyncTask चला सकते हैं जो सभी टैग्स पर पुनरावृत्त करता है, छवियों को लाता है और फिर उन्हें प्रदर्शित करता है।

यहां आप कुछ कोड पा सकते हैं जिनका आप उपयोग कर सकते हैं (लेकिन इसके लिए कुछ अनुकूलन की आवश्यकता है): https://gist.github.com/1190397


3

मैंने डेव वेब के उत्तर का उपयोग किया लेकिन इसे थोड़ा सरल किया। जब तक संसाधन आईडी आपके उपयोग-मामले में रनटाइम के दौरान समान रहेगी, तब तक वास्तव में अपने स्वयं के क्लास को लागू करने 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 को खींचने के लिए अपना स्वयं का पार्सर भी लिख सकते हैं और फिर गतिशील रूप से नए चित्र बना सकते हैं और यूआरएल में पास कर सकते हैं।


1

इसके अलावा, यदि आप स्वयं प्रतिस्थापन करना चाहते हैं, तो आपको जिस चरित्र की तलाश करनी है, वह है [want]।

लेकिन अगर आप ग्रहण का उपयोग कर रहे हैं, तो जब आप उस पत्र को टाइप करेंगे, तो यह बदल जाएगा [बदलें] बयान आपको बताता है कि यह Cp1252 के साथ संघर्ष करता है - यह एक ग्रहण बग है। इसे ठीक करने के लिए, पर जाएं

विंडो -> वरीयताएँ -> सामान्य -> ​​कार्यक्षेत्र -> पाठ फ़ाइल एन्कोडिंग,

और चुनें [UTF-8]


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/64234419a935f1effL67 पर


0

KOTLIN

उपयोग करने की संभावना भी है sufficientlysecure.htmltextview.HtmlTextView

ग्रेडल फ़ाइलों में नीचे की तरह उपयोग करें:

प्रोजेक्ट श्रेणी फ़ाइल:

repositories {
    jcenter()
}

ऐप ग्रेड फ़ाइल:

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

पिछली पंक्ति ऊपर है यदि आप बाइंडिंग एडेप्टर का उपयोग करते हैं जहां कोड इस प्रकार होगा:

@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 पृष्ठ से अधिक जानकारी और लेखकों के लिए एक बड़ा धन्यवाद !!!!!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.