Bir Android TextView'da html'den satır içi resimleri görüntülemek mümkün müdür?


87

Aşağıdaki HTML verildiğinde:

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

Görüntünün render edilmesi mümkün mü? Bu pasajı kullanırken:, mContentText.setText(Html.fromHtml(text));siyah kenarlıkları olan camgöbeği bir kutu alıyorum, bu da beni bir TextView’un img etiketinin ne olduğu hakkında bir fikir sahibi olduğuna inanmaya yönlendiriyor.


1
Gönderime göz atın
Nilanchal

Yanıtlar:


126

BelgelereHtml.fromHtml(text) bakarsanız şunu göreceksiniz:

<img>HTML'deki herhangi bir etiket, programınızın geçip gerçek görüntülerle değiştirebileceği genel bir ikame görüntü olarak görüntülenecektir.

Bu değişimi kendiniz yapmak istemiyorsanız , ayrıştırılacak metnin yanı sıra bir ve bir argüman alan diğer Html.fromHtml()yöntemi kullanabilirsiniz .Html.TagHandlerHtml.ImageGetter

Sizin durumunuzda nullolduğu gibi ayrıştırabilirsiniz , Html.TagHandlerancak Html.ImageGettervarsayılan bir uygulama olmadığı için kendinizinkini uygulamanız gerekir.

Bununla birlikte, yaşayacağınız sorun, Html.ImageGetterihtiyaçların eşzamanlı olarak çalışması gerektiğidir ve web'den görüntüler indiriyorsanız, muhtemelen bunu eşzamansız olarak yapmak isteyeceksiniz. Uygulamanızda kaynak olarak görüntülemek istediğiniz herhangi bir görüntü ekleyebilirseniz, uygulamanız ImageGetterçok daha basit hale gelir. Şunun gibi bir şeyle kurtulabilirsin:

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

Muhtemelen kaynak dizelerini kaynak kimlikleriyle eşlemek için daha akıllıca bir şey bulmak istersiniz.


4
TAMAM. Bunun yerine bir Web Görünümü kullanmanın daha kolay olduğunu buldum. Yine de tekniğinizin diğer benzer senaryolar için faydalı olduğunu görebiliyorum. Teşekkürler!
Gunnar Lium

1
kaynak kimliğini addan almanın daha akıllı yolu Resources.getIdentifier (Dize adı, String defType, String defPackage) kullanmaktır.
Timuçin

@Gunnar Lium ... ama i8mage web görünümünde görünmüyor .. !! Herhangi bir yardım ??
kgandroid

Görüntü bir sunucuda ise o zaman görüntüyü nasıl elde edebiliriz… Benim durumumda görüntü dinamik… Diğer görüntü görüntülemelerini kullanamıyorum çünkü bir görüntü olması gerektiği kesin değil…
Sourav Roy

19

Uygulamamda uyguladım, pskink .thanx'tan çokça referans aldım

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

Aşağıdaki gibi @rpgmaker yorumu bu cevabı ekledim

evet, ResolveInfo sınıfını kullanarak yapabilirsiniz

Dosyanızın zaten yüklü uygulamalarla desteklenip desteklenmediğini kontrol edin

aşağıdaki kodu kullanarak:

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
Hey, "addlevel" ve "setLevel" in tam olarak amacı nedir?
Aeefire

Görüntüleri merkezileştirmenin bir yolu var mı? Onlara dokunup yüklediğimiz resim görüntüleyici uygulamasında göstermelerini sağlasak da iyi olur.
Aspiring Dev

Sanırım sorumun içeriğini unuttun. Bir resim görüntüleyici uygulamasıyla bir resim dosyasını nasıl açacağımı biliyorum, ancak cevabınız bit eşlemleri bir TextView içine koyuyor ve anlayabildiğim kadarıyla bir kullanıcının içindeki belirli bir resme dokunduğunu ayırt etmenin bir yolu yok. Metin görünümünde çok sayıda görüntünüz varsa, bu daha çok bir sorundur. Bunu yapmanın bir yolu var mı?
Aspiring Dev

ancak bir sorun, çok yavaş kaydırması, bununla ilgili bir şeyler yapabilir miyiz?
Pratik Jamariya

smooth
scroll

16

Kullandığım şey bu, kaynak adlarınızı sertleştirmenize gerek yok ve önce uygulama kaynaklarınızda ve sonra hiçbir şey bulunamazsa stok android kaynaklarında çekilebilir kaynakları arayacak - varsayılan simgeleri ve benzerlerini kullanmanıza izin verecek.

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

 }

Hangisi bu şekilde kullanılabilir (örnek):

String myHtml = "This will display an image to the right <img src='ic_menu_more' />";
myTextview.setText(Html.fromHtml(myHtml, new ImageGetter(), null);

Bu kombinasyon, internetin AsyncTask alınmasıyla mükemmel olacaktır.
Francis Rodrigues

1
Teşekkürler! Sorunumu çözdü. Sadece yerel resimlere ihtiyacım var, bu yüzden onları çekilebilir klasöre bırakın ve html'den çağırırken resim uzantısını kaldırdığınızdan emin olun.
Dody Rachmat Wicaksono

Teşekkürler! Ancak , bu durumda sourceboşa gidebilir ve getIdentifier()çökebilir. Açık bir kontrol eklemek daha iyi.
gmk57

5

Aynı problemle karşılaştım ve oldukça temiz bir çözüm buldum: Html.fromHtml () 'den sonra, tüm etiketleri yineleyen, görüntüleri getiren ve sonra bunları görüntüleyen bir AsyncTask çalıştırabilirsiniz.

Burada kullanabileceğiniz bazı kodlar bulabilirsiniz (ancak bazı özelleştirme gerektirir): https://gist.github.com/1190397


3

Dave Webb'in cevabını kullandım ama biraz basitleştirdim. Kaynak kimlikleri, kullanım durumunuzda çalışma süresi boyunca aynı kalacağı sürece, kendi sınıf uygulamanızı yazmaya Html.ImageGetterve kaynak dizelerle uğraşmanıza gerçekten gerek yoktur .

Yaptığım şey kaynak kimliğini bir kaynak dizesi olarak kullanmaktı:

final String img = String.format("<img src=\"%s\"/>", R.drawable.your_image);
final String html = String.format("Image: %s", img);

ve doğrudan kullanın:

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

Tüm görüntülerin URL'sini almak için kendi ayrıştırıcınızı da yazabilir ve ardından dinamik olarak yeni görüntü görünümleri oluşturabilir ve URL'leri iletebilirsiniz.


1

Ayrıca, değişimi kendiniz yapmak istiyorsanız, aramanız gereken karakter [].

Ancak Eclipse kullanıyorsanız, o mektubu bir [replace] ifadesine yazdığınızda Cp1252 ile çeliştiğini söyleyerek çıldırır - bu bir Eclipse hatasıdır. Düzeltmek için şuraya gidin:

Pencere -> Tercihler -> Genel -> Çalışma Alanı -> Metin dosyası kodlaması,

ve seçin [UTF-8]


1

KOTLIN

Ayrıca kullanma imkanı da var sufficientlysecure.htmltextview.HtmlTextView

Gradle dosyalarında aşağıdaki gibi kullanın:

Proje not defteri dosyası:

repositories {
    jcenter()
}

Uygulama not defteri dosyası:

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

Xml dosyasında textView'unuzu şu şekilde değiştirin:

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

Yukarıdaki son satır, kodun aşağıdaki gibi olacağı Bağlama bağdaştırıcılarını kullanıyorsanız:

@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 sayfasından daha fazla bilgi ve yazarlara çok teşekkür ederiz !!!!!


0

Birinin kaynakların açıklayıcı olması gerektiğini düşünmesi ve birden çok dil için Spannable kullanmanın bir karmaşa olması durumunda, bazı özel görünümler yaptım

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

varsa güncellemeleri https://gist.github.com/logcat/64234419a935f1effc67 adresinden takip edin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.